Railway Operation Simulator  v2.23.3
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 /*
2  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
3  sometimes been overtaken by changes and not updated
4  Comments in .h files are believed to be accurate and up to date
5 
6  This is a source code file for "railway.exe", a railway operation
7  simulator, written originally in Borland C++ Builder 4 Professional with
8  later updates in Embarcadero C++Builder.
9  Copyright (C) 2010 Albert Ball [original development]
10 
11  This program is free software: you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program. If not, see <http://www.gnu.org/licenses/>.
23 */
24 // ---------------------------------------------------------------------------
25 #include <Classes.hpp>
26 #include <Controls.hpp>
27 #include <StdCtrls.hpp>
28 #include <Forms.hpp>
29 #include <Buttons.hpp>
30 #include <ExtCtrls.hpp>
31 #include <Menus.hpp>
32 #include <Dialogs.hpp>
33 #include <Graphics.hpp>
34 #include <ComCtrls.hpp>
35 #include <fstream>
36 #include <vector>
37 #include <algorithm> //for std::find
38 #include <vcl.h>
39 #include <windows.h>
40 #pragma hdrstop
41 
42 #include "TrackUnit.h"
43 #include "TrainUnit.h"
44 #include "GraphicUnit.h"
45 //#include "DisplayUnit.h" included in TrackUnit.h
46 #include "TextUnit.h"
47 #include "PerfLogUnit.h"
48 #include "Utilities.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  //deal with TSRs
226  if((TrackType == Simple) && Failed) //added at v2.13.0
227  {
228  Disp->GetImage()->Canvas->Draw((HLoc - Display->DisplayOffsetH) * 16, (VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
229  }
230  Utilities->CallLogPop(1332);
231 }
232 
233 // ---------------------------------------------------------------------------
234 
235 AnsiString TTrackElement::LogTrack(int Caller) const
236 // for debugging when passes as a call parameter
237 {
238  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
239  AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit23) + ",EndTrkEl,";
240 
241  return(LogString);
242 }
243 
244 // ---------------------------------------------------------------------------
245 
247  TTrackElement::TTrackElement(TFixedTrackPiece Input) : TFixedTrackPiece(Input), HLoc(-2000000000), VLoc(-2000000000), LocationName(""), ActiveTrackElementName(""),
248  Attribute(0), CallingOnSet(false), Length01(Utilities->DefaultTrackLength), Length23(-1), SpeedLimit01(Utilities->DefaultTrackSpeedLimit), SpeedLimit23(-1),
249  TrainIDOnElement(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit01(-1), TrainIDOnBridgeOrFailedPointOrigSpeedLimit23(-1), StationEntryStopLinkPos1(-1),
250  StationEntryStopLinkPos2(-1), StationEntryStopLinkPos3(-1), StationEntryStopLinkPos4(-1), SigAspect(FourAspect)
251  {
252  Failed = false; //added at v2.13.0
253  for(int x = 0; x < 4; x++)
254  {
255  ConnLinkPos[x] = -1;
256  Conn[x] = -1;
257  }
258  if((TrackType == Points) || (TrackType == Crossover) || (TrackType == Bridge))
259  {
262  }
263  }
264 
265 // ---------------------------------------------------------------------------
266 
267 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
268 {
269  if(lower.second < higher.second)
270  {
271  return(true);
272  }
273  else if(lower.second > higher.second)
274  {
275  return(false);
276  }
277  else if(lower.second == higher.second)
278  {
279  if(lower.first < higher.first)
280  {
281  return(true);
282  }
283  }
284  return(false);
285 }
286 
287 // ---------------------------------------------------------------------------
288 // PrefDirElement Functions
289 // ---------------------------------------------------------------------------
290 
291 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
292  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
293  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
294 {
295  if(!EntryExitNumber())
296  {
297  throw Exception("EXNumber failure in TPrefDirElement constructor");
298  }
301 }
302 
303 // ---------------------------------------------------------------------------
304 
305 AnsiString TPrefDirElement::LogPrefDir() const
306 // for debugging when passed as a call parameter
307 {
308  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
309  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
310  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeOrFailedPointOrigSpeedLimit01) + "," +
312 
313 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
314  return(LogString);
315 }
316 
317 // ---------------------------------------------------------------------------
318 
319 bool TPrefDirElement::EntryExitNumber() // true for valid number
320 /*
321  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
322  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
323  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
324  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
325  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
326  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
327  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
328  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
329  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
330 */
331 
332 {
333  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
334  int EXArray[16][2] =
335  {{4, 6}, {2, 8}, // horizontal & vertical
336  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
337  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
338  {1, 9}, {3, 7}}; // forward & reverse diagonals
339 
340  int EXNum = -1;
341  int Entry, Exit;
342 
343  if(ELink > -1)
344  {
345  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
346  }
347  else if(Link[2] == -1)
348  {
349  Entry = Link[0];
350  }
351  else
352  {
353  Utilities->CallLogPop(122);
354  return(false);
355  }
356  if(XLink > -1)
357  {
358  Exit = XLink;
359  }
360  else if(Link[2] == -1)
361  {
362  Exit = Link[1];
363  }
364  else
365  {
366  Utilities->CallLogPop(123);
367  return(false);
368  }
369  for(int x = 0; x < 16; x++)
370  {
371  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
372  {
373  EXNum = x;
374  }
375  }
376  if(EXNum == -1)
377  {
378  Utilities->CallLogPop(124);
379  return(false);
380  }
381  int BrNum = -1;
382 
383 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
384  the graphic for each of which is different because of the shape of the overbridge. The basic
385  entry/exit value is computed above, and this used to select only from elements with that entry/exit
386  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
387  int BrEXArray[24][2] = {
388  {4,6},{2,8},{1,9},{3,7},
389  {1,9},{3,7},{1,9},{3,7},
390  {2,8},{4,6},{2,8},{4,6}
391 */
392 
393  if(TrackType == Bridge)
394  {
395  if(EXNum == 1)
396  {
397  if(SpeedTag == 49)
398  {
399  BrNum = 1 + 16;
400  }
401  else if(SpeedTag == 54)
402  {
403  BrNum = 8 + 16;
404  }
405  else if(SpeedTag == 55)
406  {
407  BrNum = 10 + 16;
408  }
409  }
410  else if(EXNum == 0)
411  {
412  if(SpeedTag == 48)
413  {
414  BrNum = 0 + 16;
415  }
416  else if(SpeedTag == 58)
417  {
418  BrNum = 11 + 16;
419  }
420  else if(SpeedTag == 59)
421  {
422  BrNum = 9 + 16;
423  }
424  }
425  else if(EXNum == 14)
426  {
427  if(SpeedTag == 50)
428  {
429  BrNum = 2 + 16;
430  }
431  else if(SpeedTag == 52)
432  {
433  BrNum = 4 + 16;
434  }
435  else if(SpeedTag == 57)
436  {
437  BrNum = 6 + 16;
438  }
439  }
440  else if(EXNum == 15)
441  {
442  if(SpeedTag == 51)
443  {
444  BrNum = 3 + 16;
445  }
446  else if(SpeedTag == 53)
447  {
448  BrNum = 7 + 16;
449  }
450  else if(SpeedTag == 56)
451  {
452  BrNum = 5 + 16;
453  }
454  }
455  }
456  if(BrNum == -1)
457  {
458  EXNumber = EXNum;
459  }
460  else
461  {
462  EXNumber = BrNum;
463  }
464  Utilities->CallLogPop(125);
465  return(true);
466 }
467 
468 // ---------------------------------------------------------------------------
469 
471 /*
472  This is the basic track graphic for use in plotting the original graphic during route flashing.
473  Enter with all set apart from EXGraphic & EntryDirectionGraphic
474 */
475 {
476  if(SpeedTag == 64)
477  {
478  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
479 
480  }
481  if(SpeedTag == 65)
482  {
483  return(RailGraphics->LinkGraphicsPtr[17]);
484  }
485  if(SpeedTag == 66)
486  {
487  return(RailGraphics->LinkGraphicsPtr[18]);
488  }
489  if(SpeedTag == 67)
490  {
491  return(RailGraphics->LinkGraphicsPtr[19]);
492  }
493  if(SpeedTag == 80)
494  {
495  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
496 
497  }
498  if(SpeedTag == 81)
499  {
500  return(RailGraphics->LinkGraphicsPtr[21]);
501  }
502  if(SpeedTag == 82)
503  {
504  return(RailGraphics->LinkGraphicsPtr[22]);
505  }
506  if(SpeedTag == 83)
507  {
508  return(RailGraphics->LinkGraphicsPtr[23]);
509  }
510  if(SpeedTag == 84)
511  {
512  return(RailGraphics->LinkGraphicsPtr[24]);
513  }
514  if(SpeedTag == 85)
515  {
516  return(RailGraphics->LinkGraphicsPtr[25]);
517  }
518  if(SpeedTag == 86)
519  {
520  return(RailGraphics->LinkGraphicsPtr[26]);
521  }
522  if(SpeedTag == 87)
523  {
524  return(RailGraphics->LinkGraphicsPtr[27]);
525  }
526  if(SpeedTag == 129)
527  {
528  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
529 
530  }
531  if(SpeedTag == 130)
532  {
533  return(RailGraphics->LinkGraphicsPtr[29]);
534  }
535  if(XLinkPos == -1) // not set, could be first element or last element = leading point
536  {
537 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
538 // Points & don't want to display these)
539  if(Link[2] != -1)
540  {
541  return(0); // i.e. complex element, don't display
542  }
543  else
544  {
545  if(!EntryExitNumber())
546  {
547  throw Exception("Error in EntryExitNumber 4");
548  }
549  else
550  {
552  }
553  }
554  }
555  if(EXNumber > 15) // underbridge
556  {
557  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
558  }
559  else
560  {
562  }
563 }
564 
565 // ---------------------------------------------------------------------------
566 
568 /*
569  As above but for PrefDir graphics.
570 */
571 {
572  if(SpeedTag == 64)
573  {
574  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
575 
576  }
577  if(SpeedTag == 65)
578  {
580  }
581  if(SpeedTag == 66)
582  {
584  }
585  if(SpeedTag == 67)
586  {
588  }
589  if(SpeedTag == 80)
590  {
591  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
592 
593  }
594  if(SpeedTag == 81)
595  {
597  }
598  if(SpeedTag == 82)
599  {
601  }
602  if(SpeedTag == 83)
603  {
605  }
606  if(SpeedTag == 84)
607  {
609  }
610  if(SpeedTag == 85)
611  {
613  }
614  if(SpeedTag == 86)
615  {
617  }
618  if(SpeedTag == 87)
619  {
621  }
622  if(SpeedTag == 129)
623  {
624  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
625 
626  }
627  if(SpeedTag == 130)
628  {
630  }
631  if(XLinkPos == -1) // not set, could be first element or last element = leading point
632  {
633 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
634  if(Link[2] != -1)
635  {
636  return(0); // i.e. complex element, don't display
637  }
638  else
639  {
640  if(!EntryExitNumber())
641  {
642  throw Exception("Error in EntryExitNumber 5");
643  }
644  else
645  {
647  }
648  }
649  }
650  if(EXNumber > 15) // underbridge
651  {
653  }
654  else
655  {
657  }
658 }
659 
660 // ---------------------------------------------------------------------------
661 
662 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
663 /*
664  As above but for route graphics.
665 */
666 {
667  if(!AutoSigsFlag && !PrefDirRoute)
668  {
669  if(SpeedTag == 64)
670  {
671  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
672  }
673  if(SpeedTag == 65)
674  {
676  }
677  if(SpeedTag == 66)
678  {
680  }
681  if(SpeedTag == 67)
682  {
684  }
685  if(SpeedTag == 80)
686  {
687  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
688  }
689  if(SpeedTag == 81)
690  {
692  }
693  if(SpeedTag == 82)
694  {
696  }
697  if(SpeedTag == 83)
698  {
700  }
701  if(SpeedTag == 84)
702  {
704  }
705  if(SpeedTag == 85)
706  {
708  }
709  if(SpeedTag == 86)
710  {
712  }
713  if(SpeedTag == 87)
714  {
716  }
717  if(SpeedTag == 129)
718  {
719  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
720  }
721  if(SpeedTag == 130)
722  {
724  }
725  if(XLinkPos == -1) // not set, could be first element or last element = leading point
726  {
727  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
728  if(Link[2] != -1)
729  {
730  return(0); // i.e. complex element, don't display
731  }
732  else
733  {
734  if(!EntryExitNumber())
735  {
736  throw Exception("Error in EntryExitNumber 6");
737  }
738  else
739  {
741  }
742  }
743  }
744  if(EXNumber > 15) // underbridge
745  {
747  }
748  else
749  {
751  }
752  }
753 
754  else if(!AutoSigsFlag && PrefDirRoute)
755  {
756  if(SpeedTag == 64)
757  {
758  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
759  }
760  if(SpeedTag == 65)
761  {
763  }
764  if(SpeedTag == 66)
765  {
767  }
768  if(SpeedTag == 67)
769  {
771  }
772  if(SpeedTag == 80)
773  {
774  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
775  }
776  if(SpeedTag == 81)
777  {
779  }
780  if(SpeedTag == 82)
781  {
783  }
784  if(SpeedTag == 83)
785  {
787  }
788  if(SpeedTag == 84)
789  {
791  }
792  if(SpeedTag == 85)
793  {
795  }
796  if(SpeedTag == 86)
797  {
799  }
800  if(SpeedTag == 87)
801  {
803  }
804  if(SpeedTag == 129)
805  {
806  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
807  }
808  if(SpeedTag == 130)
809  {
811  }
812  if(XLinkPos == -1) // not set, could be first element or last element = leading point
813  {
814  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
815  if(Link[2] != -1)
816  {
817  return(0); // i.e. complex element, don't display
818  }
819  else
820  {
821  if(!EntryExitNumber())
822  {
823  throw Exception("Error in EntryExitNumber 10");
824  }
825  else
826  {
828  }
829  }
830  }
831  if(EXNumber > 15) // underbridge
832  {
834  }
835  else
836  {
838  }
839  }
840 
841  else
842  {
843  if(SpeedTag == 64)
844  {
845  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
846  }
847  if(SpeedTag == 65)
848  {
850  }
851  if(SpeedTag == 66)
852  {
854  }
855  if(SpeedTag == 67)
856  {
858  }
859  if(SpeedTag == 80)
860  {
861  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
862 
863  }
864  if(SpeedTag == 81)
865  {
867  }
868  if(SpeedTag == 82)
869  {
871  }
872  if(SpeedTag == 83)
873  {
875  }
876  if(SpeedTag == 84)
877  {
879  }
880  if(SpeedTag == 85)
881  {
883  }
884  if(SpeedTag == 86)
885  {
887  }
888  if(SpeedTag == 87)
889  {
891  }
892  if(SpeedTag == 129)
893  {
894  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
895 
896  }
897  if(SpeedTag == 130)
898  {
900  }
901  if(XLinkPos == -1) // not set, could be first element or last element = leading point
902  {
903  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
904  if(Link[2] != -1)
905  {
906  return(0); // i.e. complex element, don't display
907  }
908  else
909  {
910  if(!EntryExitNumber())
911  {
912  throw Exception("Error in EntryExitNumber 11");
913  }
914  else
915  {
917  }
918  }
919  }
920  if(EXNumber > 15) // underbridge
921  {
923  }
924  else
925  {
927  }
928  }
929 }
930 
931 // ---------------------------------------------------------------------------
932 
934 /*
935  As above but for route flashing graphics. (Disused - now combined with above)
936 */
937 {
938  if(SpeedTag == 64)
939  {
940  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
941 
942  }
943  if(SpeedTag == 65)
944  {
946  }
947  if(SpeedTag == 66)
948  {
950  }
951  if(SpeedTag == 67)
952  {
954  }
955  if(SpeedTag == 80)
956  {
957  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
958 
959  }
960  if(SpeedTag == 81)
961  {
963  }
964  if(SpeedTag == 82)
965  {
967  }
968  if(SpeedTag == 83)
969  {
971  }
972  if(SpeedTag == 84)
973  {
975  }
976  if(SpeedTag == 85)
977  {
979  }
980  if(SpeedTag == 86)
981  {
983  }
984  if(SpeedTag == 87)
985  {
987  }
988  if(SpeedTag == 129)
989  {
990  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
991 
992  }
993  if(SpeedTag == 130)
994  {
996  }
997  if(XLinkPos == -1) // not set, could be first element or last element = leading point
998  {
999 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
1000  if(Link[2] != -1)
1001  {
1002  return(0); // i.e. complex element, don't display
1003  }
1004  else
1005  {
1006  if(!EntryExitNumber())
1007  {
1008  throw Exception("Error in EntryExitNumber 7");
1009  }
1010  else
1011  {
1013  }
1014  }
1015  }
1016  if(EXNumber > 15) // underbridge
1017  {
1019  }
1020  else
1021  {
1023  }
1024 }
1025 
1026 // ---------------------------------------------------------------------------
1027 
1029 /*
1030  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1031 */
1032 {
1033  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1034  {
1036  }
1037  else
1038  {
1039  throw Exception("Error in EntryExitNumber 8");
1040  }
1041 }
1042 
1043 // ---------------------------------------------------------------------------
1044 
1045 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1046 /*
1047  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1048 */
1049 {
1050  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1051  {
1052  if(!AutoSigsFlag && !PrefDirRoute)
1053  {
1055  }
1056  else if(!AutoSigsFlag && PrefDirRoute)
1057  {
1059  }
1060  else
1061  {
1063  }
1064  }
1065  else
1066  {
1067  throw Exception("Error in EntryExitNumber 9");
1068  }
1069 }
1070 
1071 // ---------------------------------------------------------------------------
1072 
1074 /*
1075  Set == operator when TrackVectorPosition, ELink & XLink all same
1076 */
1077 {
1078  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1079  {
1080  return(true);
1081  }
1082  else
1083  {
1084  return(false);
1085  }
1086 }
1087 
1088 // ---------------------------------------------------------------------------
1089 
1091 /*
1092  Set != operator when any of TrackVectorPosition, ELink or XLink different
1093 */
1094 {
1095  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1096  {
1097  return(false);
1098  }
1099  else
1100  {
1101  return(true);
1102  }
1103 }
1104 
1105 // ---------------------------------------------------------------------------
1106 
1107 int TPrefDirElement::GetRouteColour(Graphics::TBitmap *EXG)
1108 { //returns 1 for red, 2 for green & 3 for blue , or 0 for no match (i.e. using it other than on a route)
1109  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",GetRouteColour");
1110  if(GetRouteGraphicPtr(0,0) == EXG) //AutoSignals, PrefDirRoute
1111  {
1112  Utilities->CallLogPop(2566);
1113  return(1);
1114  }
1115  if(GetRouteGraphicPtr(0,1) == EXG)
1116  {
1117  Utilities->CallLogPop(2567);
1118  return(2);
1119  }
1120  if(GetRouteGraphicPtr(1,0) == EXG)
1121  {
1122  Utilities->CallLogPop(2568);
1123  return(3);
1124  }
1125  if(GetRouteGraphicPtr(1,1) == EXG)
1126  {
1127  Utilities->CallLogPop(2569);
1128  return(3);
1129  }
1130  Utilities->CallLogPop(2570);
1131  return(0);
1132 }
1133 
1134 // ---------------------------------------------------------------------------
1135 // Track functions
1136 // ---------------------------------------------------------------------------
1137 
1138 // ---------------------------------------------------------------------------
1139 
1141 {
1142  TypeOfRoute = 0;
1143  ReducedTimePenalty = false;
1144  BarrierState = Up;
1145  ChangeDuration = 0.0;
1146  BaseElementSpeedTag = 1;
1147  HLoc = 0;
1148  VLoc = 0;
1149  StartTime = TDateTime(0);
1150 }
1151 
1152 // ---------------------------------------------------------------------------
1153 
1155 {
1156 // CurrentSpeedButtonTag = 0; //not assigned yet
1157 
1158  HLocMin = 2000000000;
1159  VLocMin = 2000000000;
1160  HLocMax = -2000000000;
1161  VLocMax = -2000000000;
1162  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1163  CopyFlag = false; // only true for copying, so names aren't copied
1164  AnsiString NL = '\n';
1165 
1166  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable, perhaps because of failed points; " + NL + NL +
1167  "reachable but too far ahead or with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1168  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1169  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1170 
1175  LengthHeatMapFlag = false;
1176  SpeedHeatMapFlag = false;
1177 
1178  int InternalLinkCheckArray[9][2] =
1179  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1180 
1181 /* array of valid link values for 'old' location and 'new' location, where
1182  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1183 
1184  for(int x = 0; x < 9; x++)
1185  {
1186  for(int y = 0; y < 2; y++)
1187  {
1188  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1189  }
1190  }
1191 
1192 // Platform and default track element values
1193  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1194 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1195  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1196  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1197  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1198  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16 << 18 << 19 << 20 << 21 << 22 << 23 << 24
1199  << 25 << 26 << 27 << 28 << 29 << 30 << 31 << 32 << 33 << 34 << 35 << 36 << 37 << 38 << 39 << 40 << 41 << 42 << 43 << 44 << 45 << 46 << 47
1200  << 60 << 61 << 62 << 63 << 64 << 65 << 66 << 67 << 68 << 69 << 70 << 71 << 72 << 73 << 74 << 75 << 80 << 81 << 82 << 83 << 84 << 85 << 86
1201  << 87 << 125 << 126 << 127 << 128 << 132 << 133 << 134 << 135 << 136 << 137 << 138 << 139
1202  << 140 << 141 << 142 << 143; //prevent bridges, footcrossings, platforms, concourses, non-station named locs, parapets, level crossings & gaps
1203  //gaps cause a mass of problems as links not adjacent - interferes with cut/copy/paste & duplicate names found
1204  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1205 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1206 
1207  int HVArray[10][2] =
1208  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1209 
1210  for(int x = 0; x < 10; x++)
1211  {
1212  for(int y = 0; y < 2; y++)
1213  {
1214  LinkHVArray[x][y] = HVArray[x][y];
1215  }
1216  }
1217  TrackFinished = false;
1218 // DistancesSet = false;
1219 
1220  TSigElement TempSigTable[40] = // original four aspect
1221  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1222  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1223 
1224  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1225  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1226 
1229 
1230  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1231  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1232 
1233  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1234  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1235  {75, 4, RailGraphics->gl75}};
1236 
1237  for(int x = 0; x < 40; x++)
1238  {
1239  SigTable[x] = TempSigTable[x];
1240  }
1241 
1242  TSigElement TempSigTableThreeAspect[40] =
1243  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1244  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1245 
1246  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1247  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1248 
1249  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1250  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1251 
1252  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1253  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1254 
1255  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1256  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1257  {75, 4, RailGraphics->gl75}};
1258 
1259  for(int x = 0; x < 40; x++)
1260  {
1261  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1262  }
1263 
1264  TSigElement TempSigTableTwoAspect[40] =
1265  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1266  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1267 
1268  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1269  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1270 
1271  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1272  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1273 
1274  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1275  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1276 
1277  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1278  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1279  {75, 4, RailGraphics->gl75}};
1280 
1281  for(int x = 0; x < 40; x++)
1282  {
1283  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1284  }
1285 
1286  TSigElement TempSigTableGroundSignal[40] =
1290 
1294 
1298 
1302 
1303  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1306 
1307  for(int x = 0; x < 40; x++)
1308  {
1309  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1310  }
1311 
1312  TSigElement TempFailedSigTable[8] = // added at v2.13.0
1313  {{68, 0, RailGraphics->FSig68}, {69, 0, RailGraphics->FSig69}, {70, 0, RailGraphics->FSig70}, {71, 0, RailGraphics->FSig71}, {72, 0, RailGraphics->FSig72},
1314  {73, 0, RailGraphics->FSig73}, {74, 0, RailGraphics->FSig74}, {75, 0, RailGraphics->FSig75}};
1315 
1316  for(int x = 0; x < 8; x++)
1317  {
1318  FailedSigTable[x] = TempFailedSigTable[x];
1319  }
1320 
1321  TSigElement TempFailedGroundSigTable[8] = // added at v2.14.0 to allow ground signals to fail
1322  {{68, 0, RailGraphics->FGSig68}, {69, 0, RailGraphics->FGSig69}, {70, 0, RailGraphics->FGSig70}, {71, 0, RailGraphics->FGSig71}, {72, 0, RailGraphics->FGSig72},
1323  {73, 0, RailGraphics->FGSig73}, {74, 0, RailGraphics->FGSig74}, {75, 0, RailGraphics->FGSig75}};
1324 
1325  for(int x = 0; x < 8; x++)
1326  {
1327  FailedGroundSigTable[x] = TempFailedGroundSigTable[x];
1328  }
1329 
1330 /*
1331  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1332  a single location. These are as follows:-
1333  Directly Adjacent = up, down, left or right - NOT diagonal.
1334  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1335  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1336  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1337 
1338  //t 76
1339  //b 77
1340  //l 78
1341  //r 79
1342  //c 96
1343  //v fb 129
1344  //h fb 130
1345  //v underpass 145
1346  //h underpass 146
1347  //n 131
1348 */
1349 
1350  int Tag76[25][3] =
1351  {{-1, 0, 96}, // c top plat
1352  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1353  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1354  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1355  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1356  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1357  {0, 0, 129}, {0, -1, 145}, // v up
1358  {0, 0, 145}};
1359 
1360  for(int x = 0; x < 25; x++)
1361  {
1362  for(int y = 0; y < 3; y++)
1363  {
1364  Tag76Array[x][y] = Tag76[x][y];
1365  }
1366  }
1367 
1368  int Tag77[25][3] =
1369  {{-1, 0, 96}, // c bot plat
1370  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1371  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1372  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1373  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1374  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1375  {0, 0, 129}, {0, 1, 145}, // v up
1376  {0, 0, 145}};
1377 
1378  for(int x = 0; x < 25; x++)
1379  {
1380  for(int y = 0; y < 3; y++)
1381  {
1382  Tag77Array[x][y] = Tag77[x][y];
1383  }
1384  }
1385 
1386  int Tag78[25][3] =
1387  {{-1, 0, 96}, // c left plat
1388  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1389  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1390  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1391  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1392  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1393  {0, 0, 130}, {-1, 0, 146}, // h up
1394  {0, 0, 146}};
1395 
1396  for(int x = 0; x < 25; x++)
1397  {
1398  for(int y = 0; y < 3; y++)
1399  {
1400  Tag78Array[x][y] = Tag78[x][y];
1401  }
1402  }
1403 
1404  int Tag79[25][3] =
1405  {{-1, 0, 96}, // c right plat
1406  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1407  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1408  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1409  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1410  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1411  {0, 0, 130}, {1, 0, 146}, // h up
1412  {0, 0, 146}};
1413 
1414  for(int x = 0; x < 25; x++)
1415  {
1416  for(int y = 0; y < 3; y++)
1417  {
1418  Tag79Array[x][y] = Tag79[x][y];
1419  }
1420  }
1421 
1422  int Tag96[28][3] =
1423  {{-1, 0, 96}, // c //concourse
1424  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1425  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1426  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1427  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1428  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1429  {0, -1, 129}, {1, 0, 130}, // h fb
1430  {-1, 0, 130}, {0, 1, 145}, // v up
1431  {0, -1, 145}, {1, 0, 146}, // h up
1432  {-1, 0, 146}};
1433 
1434  for(int x = 0; x < 28; x++)
1435  {
1436  for(int y = 0; y < 3; y++)
1437  {
1438  Tag96Array[x][y] = Tag96[x][y];
1439  }
1440  }
1441 
1442  int Tag129[8][3] = // vert fb
1443  {{0, -1, 96}, // c
1444  {0, -1, 77}, // b
1445  {0, -1, 129}, // v fb
1446 
1447  {0, 1, 96}, // c
1448  {0, 1, 76}, // t
1449  {0, 1, 129}, // v fb
1450 
1451  {0, 0, 76}, // t
1452  {0, 0, 77}}; // b
1453 
1454  for(int x = 0; x < 8; x++)
1455  {
1456  for(int y = 0; y < 3; y++)
1457  {
1458  Tag129Array[x][y] = Tag129[x][y];
1459  }
1460  }
1461 
1462  int Tag145[8][3] = // vert up
1463  {{0, -1, 96}, // c
1464  {0, -1, 77}, // b
1465  {0, -1, 145}, // v fb
1466 
1467  {0, 1, 96}, // c
1468  {0, 1, 76}, // t
1469  {0, 1, 145}, // v fb
1470 
1471  {0, 0, 76}, // t
1472  {0, 0, 77}}; // b
1473 
1474  for(int x = 0; x < 8; x++)
1475  {
1476  for(int y = 0; y < 3; y++)
1477  {
1478  Tag145Array[x][y] = Tag145[x][y];
1479  }
1480  }
1481 
1482  int Tag130[8][3] = // hor fb
1483  {{-1, 0, 96}, // c
1484  {-1, 0, 79}, // r
1485  {-1, 0, 130}, // h fb
1486 
1487  {1, 0, 96}, // c
1488  {1, 0, 78}, // l
1489  {1, 0, 130}, // h fb
1490 
1491  {0, 0, 78}, // l
1492  {0, 0, 79}}; // r
1493 
1494  for(int x = 0; x < 8; x++)
1495  {
1496  for(int y = 0; y < 3; y++)
1497  {
1498  Tag130Array[x][y] = Tag130[x][y];
1499  }
1500  }
1501 
1502  int Tag146[8][3] = // hor up
1503  {{-1, 0, 96}, // c
1504  {-1, 0, 79}, // r
1505  {-1, 0, 146}, // h fb
1506 
1507  {1, 0, 96}, // c
1508  {1, 0, 78}, // l
1509  {1, 0, 146}, // h fb
1510 
1511  {0, 0, 78}, // l
1512  {0, 0, 79}}; // r
1513 
1514  for(int x = 0; x < 8; x++)
1515  {
1516  for(int y = 0; y < 3; y++)
1517  {
1518  Tag146Array[x][y] = Tag146[x][y];
1519  }
1520  }
1521 
1522  int Tag131[4][3] =
1523  {{-1, 0, 131}, // n
1524  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1525 
1526  for(int x = 0; x < 4; x++)
1527  {
1528  for(int y = 0; y < 3; y++)
1529  {
1530  Tag131Array[x][y] = Tag131[x][y];
1531  }
1532  }
1533 
1534  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1535  {
1536  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1537  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1538  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1539  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1540  140, 144, 145, 146
1541  };
1542 
1543  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1544  {
1545  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1546  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1547  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1548  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1549  141, 144, 145, 146
1550  };
1551 
1552  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1553  {
1554  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1555  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1556  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1557  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1558  141, 144, 146, 145
1559  };
1560 
1561  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1562  {
1563  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1564  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1565  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1566  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1567  140, 144, 146, 145
1568  };
1569 
1570  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1571  {
1572  FlipArray[x] = InternalFlipArray[x];
1573  MirrorArray[x] = InternalMirrorArray[x];
1574  RotRightArray[x] = InternalRotRightArray[x];
1575  RotLeftArray[x] = InternalRotLeftArray[x];
1576  }
1577 }
1578 
1579 // ---------------------------------------------------------------------------
1581 {
1582 // delete TrackVectorPtr;
1583 // delete FixedTrackArrayPtr;
1584  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1585 
1586  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1587  {
1588  delete UGMIt->second;
1589  UGMIt++;
1590  }
1591  delete GapFlashGreen;
1592  delete GapFlashRed;
1593  // all the rest are cleared by the relevant automatic destructors
1594 }
1595 
1596 // ---------------------------------------------------------------------------
1597 
1599 {
1600  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1601  {
1602 // loc 0 not used, set to bmSolidBgnd
1606 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1626  };
1627 
1628  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1629  {
1630 // loc 0 not used, set to smSolidBgnd
1634 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1653  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1654  };
1655 
1656 // track types
1657  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1658  {
1659  Erase, // 1 0
1660  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1661  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1662  Crossover, Crossover, // 2 15-16
1663  Unused, // 17 (was for text in earlier development) //1 17
1666  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1670  Platform, Platform, Platform, Platform, // 4 76-79
1673  Concourse, // 1 96
1676  Simple, Simple, Simple, Simple, // 4 125-128
1677  FootCrossing, FootCrossing, // 2 129-130
1678  NamedNonStationLocation, // 1 131
1679  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1680  Simple, Simple, Simple, Simple, // 4 140-143
1681  LevelCrossing, // 1 144
1682  FootCrossing, FootCrossing // 2 145 & 146
1683  };
1684 
1685 // links
1686  int Links[FirstUnusedSpeedTagNumber][4] =
1687  {{-1, -1, -1, -1}, // erase element
1688  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1689  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1690 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1691  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1692  {-1, -1, -1, -1}, // unused
1693  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1694  {2, 7, -1, -1}, // simple
1695  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1696 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1697 // (or right diverging if no straight)
1698  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1699  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1700  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1701  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1702  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1703  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1704  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1705  {-1, -1, -1, -1}, // Concourse
1706  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1707  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1708  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1709  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1710  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1711  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1712  {-1, -1, -1, -1}, // NamedNonStationLocation
1713  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1714 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1715  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1716  {-1, -1, -1, -1}, // level crossing
1717  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1718  };
1719 
1721  {{NotSet, NotSet, NotSet, NotSet}, // unused
1725  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1727  {NotSet, NotSet, NotSet, NotSet}, // unused
1731  {Connection, Connection, NotSet, NotSet}, // simple
1735  {Lead, Trail, Lead, Trail}, // points
1737  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1745  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1751  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1760  {Connection, Connection, NotSet, NotSet}, // Arrows
1762  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1764  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1766  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1767  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1768  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1769  };
1770 
1771  for(int x = 0; x < 17; x++)
1772  {
1773  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1774  }
1775  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1776 // 17 was the old text value so don't want any graphics (now disused)
1777  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1778  {
1779  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1780  }
1781 }
1782 
1783 // ---------------------------------------------------------------------------
1784 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1785  ExistingGraphicLoaded(false), Width(16), Height(16)
1786 {
1787  OriginalGraphic = new Graphics::TBitmap;
1788  OriginalGraphic->PixelFormat = pf8bit;
1789  OriginalGraphic->Width = Width;
1790  OriginalGraphic->Height = Height;
1791  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1792 }
1793 
1794 // ---------------------------------------------------------------------------
1795 
1796 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1797  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1798 {
1799  OriginalGraphic = new Graphics::TBitmap;
1800  OriginalGraphic->PixelFormat = pf8bit;
1801  OriginalGraphic->Width = Width;
1802  OriginalGraphic->Height = Height;
1803  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1804 }
1805 
1806 // ---------------------------------------------------------------------------
1807 
1809 {
1810  delete OriginalGraphic;
1811 }
1812 
1813 // ---------------------------------------------------------------------------
1814 
1815 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1816 {
1817  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1818  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1819  VPos = VPosIn;
1820  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1821 
1822  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1823  SourceRect.init(Left, Top, Left + Width, Top + Height);
1824  ScreenSourceSet = true;
1825  Utilities->CallLogPop(422);
1826 }
1827 
1828 // ---------------------------------------------------------------------------
1829 
1831 {
1832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1833  if(!OverlayLoaded)
1834  {
1835  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1836  }
1837  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1838  {
1839  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1840  }
1841  if(!ScreenSourceSet)
1842  {
1843  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1844  }
1845  if(ExistingGraphicLoaded) // can only call one of the load functions
1846  {
1847  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1848  }
1849  if(OverlayPlotted) // don't load from screen if overlay plotted
1850  {
1851  Utilities->CallLogPop(775);
1852  return;
1853  }
1854  TRect DestRect(0, 0, Width, Height);
1855 
1857  OriginalLoaded = true;
1858  ScreenGraphicLoaded = true;
1859  Utilities->CallLogPop(423);
1860 }
1861 
1862 // ---------------------------------------------------------------------------
1863 
1864 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1865 /*
1866  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1867 */
1868 {
1869  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1870  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1871  if(!OverlayLoaded)
1872  {
1873  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1874  }
1875  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1876  {
1877  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1878  }
1879  if(ScreenGraphicLoaded) // can only call one of the load functions
1880  {
1881  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1882  }
1883  Width = WidthIn;
1884  Height = HeightIn;
1885  OriginalGraphic->Width = Width;
1886  OriginalGraphic->Height = Height;
1887  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1888  VPos += VOffset;
1889  TRect DestRect(0, 0, Width, Height);
1890 
1891  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1892  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1893  OriginalLoaded = true;
1894  ExistingGraphicLoaded = true;
1895  Utilities->CallLogPop(424);
1896 }
1897 
1898 // ---------------------------------------------------------------------------
1899 
1900 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1901 {
1902  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1903  OverlayGraphic = Overlay;
1904  OverlayLoaded = true;
1905  Utilities->CallLogPop(425);
1906 }
1907 
1908 // ---------------------------------------------------------------------------
1909 
1911 {
1912  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1913  if(!OverlayLoaded)
1914  {
1915  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1916  }
1917  if(!OverlayPlotted)
1918  {
1919  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1920  Disp->Update();
1921  OverlayPlotted = true;
1922  }
1923  Utilities->CallLogPop(426);
1924 }
1925 
1926 // ---------------------------------------------------------------------------
1927 
1929 {
1930  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1931  if(OverlayPlotted)
1932  {
1933  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1934  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1935  {
1936  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1937  }
1938  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1939  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1940  OverlayPlotted = false;
1941  }
1942  Utilities->CallLogPop(427);
1943 }
1944 
1945 // ---------------------------------------------------------------------------
1946 
1948 {
1949  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1950  bool TrackPresent = false;
1951 
1952  if(InactiveTrackVector.size() != 0)
1953  {
1954  Utilities->CallLogPop(1333);
1955  return(false);
1956  }
1957  else if(TrackVector.size() == 0)
1958  {
1959  Utilities->CallLogPop(1334);
1960  return(true);
1961  }
1962  else
1963  {
1964  for(unsigned int x = 0; x < TrackVector.size(); x++)
1965  {
1966  if((TrackElementAt(1042, x).SpeedTag != 0))
1967  {
1968  TrackPresent = true;
1969  }
1970  }
1971  }
1972  Utilities->CallLogPop(1335);
1973  return(!TrackPresent);
1974 }
1975 
1976 // ---------------------------------------------------------------------------
1977 
1978 bool TTrack::NoActiveTrack(int Caller)
1979 {
1980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1981  bool TrackPresent = false;
1982 
1983  if(TrackVector.size() == 0)
1984  {
1985  Utilities->CallLogPop(1582);
1986  return(true);
1987  }
1988  else
1989  {
1990  for(unsigned int x = 0; x < TrackVector.size(); x++)
1991  {
1992  if((TrackElementAt(1043, x).SpeedTag != 0))
1993  {
1994  TrackPresent = true;
1995  }
1996  break;
1997  }
1998  }
1999  Utilities->CallLogPop(1583);
2000  return(!TrackPresent);
2001 }
2002 
2003 // ---------------------------------------------------------------------------
2004 
2005 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, TOnePrefDir *TempEveryPrefDir, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
2006 {
2007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
2008  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2009  TrackEraseSuccessfulFlag = false;
2010 // TrackEraseSuccessfulFlag used for any element erased, used to set TrackFinished to false if a track element erased (nneded even if track reinstated as otherwise all connections etc. lost)
2011 
2012 //After v2.23.2 if location has both active & inactive elements then the active element will be put back afterwards (so first erase just for inactives) but if a foot crossing
2013 //replace active with just the corresponding track (because crossings are active)
2014  ErasedTrackVectorPosition = -1; // marker for no element erased
2015  AnsiString SName = "", ErrorString;
2017  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
2018  TTrackMapIterator TrackMapPtr;
2019  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
2020  TTrackElement TempTrackElement; //save element in case need to reinstate it
2021  bool ActiveElementErased = false;
2022  bool InactiveElementErased = false;
2023  bool FootCrossingErased = false;
2024 
2025  if(TrackVector.size() != 0)
2026  {
2027  TrackMapKeyPair.first = HLocInput;
2028  TrackMapKeyPair.second = VLocInput;
2029  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
2030  if(TrackMapPtr != TrackMap.end())
2031  {
2032  bool FoundFlag;
2033  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
2034  if(FoundFlag) // should find it as it's in the map
2035  {
2036  TempTrackElement = TrackElementAt(1690, VecPos);
2037  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
2038  {
2039  SName = TrackElementAt(1, VecPos).LocationName; //need to erase this even if null
2040  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
2041  if(ErrorString != "")
2042  {
2043  throw Exception(ErrorString + " for EraseTrackElement 1");
2044  }
2045  LocationNameMultiMap.erase(SNIt);
2046  }
2047  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
2048  // ensure erase vector element before map element as iterator no longer valid after a map erase
2049  TrackMap.erase(TrackMapPtr);
2050  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
2051  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2053  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
2054  if(SName != "")
2055  {
2056  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2057  int HPos, VPos;
2058  if(TextHandler->FindText(1, SName, HPos, VPos))
2059  {
2060  if(TextHandler->TextErase(5, HPos, VPos, SName))
2061  {
2062  ;
2063  } // condition not used
2064 
2065  }
2066  }
2067  ErasedTrackVectorPosition = VecPos;
2068  TrackEraseSuccessfulFlag = true;
2069  ActiveElementErased = true;
2070  if(TempTrackElement.TrackType == FootCrossing)
2071  {
2072  FootCrossingErased = true;
2073  }
2074  }
2075  }
2076  }
2077  if(InactiveTrackVector.size() != 0)
2078  {
2079  unsigned int VecPos;
2080  InactiveTrackMapKeyPair.first = HLocInput;
2081  InactiveTrackMapKeyPair.second = VLocInput;
2082  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2083  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2084  {
2085  SName = "";
2086  VecPos = InactiveTrack2MultiMapIterator->second;
2087  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2088  {
2089  SName = InactiveTrackElementAt(1, VecPos).LocationName; //need to erase this even if null
2090  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2091  if(ErrorString != "")
2092  {
2093  throw Exception(ErrorString + " for EraseTrackElement 2A");
2094  }
2095  LocationNameMultiMap.erase(SNIt);
2096  }
2097  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2098  // ensure erase vector element before map element as iterator no longer valid after a map erase
2099  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2100  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2101  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2103  TrackEraseSuccessfulFlag = true;
2104  InactiveElementErased = true;
2105  if(SName != "")
2106  {
2107  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2108  int HPos, VPos;
2109  if(TextHandler->FindText(2, SName, HPos, VPos))
2110  {
2111  if(TextHandler->TextErase(6, HPos, VPos, SName))
2112  {
2113  ;
2114  } // condition not used
2115  }
2116  }
2117  }
2118  if(InactiveTrackVector.size() != 0) // need to check again as could be 2 platforms at the location & both need to be erased
2119  {
2120  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2121  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2122  {
2123  SName = "";
2124  VecPos = InactiveTrack2MultiMapIterator->second;
2125  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2126  {
2127  SName = InactiveTrackElementAt(3, VecPos).LocationName; //need to erase this even if null
2128  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2129  if(ErrorString != "")
2130  {
2131  throw Exception(ErrorString + " for EraseTrackElement 2B");
2132  }
2133  LocationNameMultiMap.erase(SNIt);
2134  }
2135  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2136  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2137  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2139  TrackEraseSuccessfulFlag = true;
2140  InactiveElementErased = true;
2141  if(SName != "")
2142  {
2143  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2144  int HPos, VPos;
2145  if(TextHandler->FindText(3, SName, HPos, VPos))
2146  {
2147  if(TextHandler->TextErase(7, HPos, VPos, SName))
2148  {
2149  ;
2150  } // condition not used
2151  }
2152  }
2153  }
2154  }
2155  }
2156  //here reinstate the track element if ActiveElementErased AND either (InactiveElementErased or FootCrossingErased)
2157  bool TrackPlottedFlag = false;
2158  if(ActiveElementErased && InactiveElementErased) //reinstate the original element, set ErasedTrackVectorPosition to -1 so prefdirs not affected
2159  {
2160  if(!FootCrossingErased) //new element will be plotted below, without this the below plot won't work and CheckLocationNameMultiMap will fail
2161  {
2162  PlotAndAddTrackElement(4, TempTrackElement.SpeedTag, 0, HLocInput, VLocInput, TrackPlottedFlag, false, false);
2163  //0 for Aspect indicates adding and not pasting
2164  TTrackElement &TE = GetTrackElementFromTrackMap(9, HLocInput, VLocInput);
2165  TE.SigAspect = TempTrackElement.SigAspect;
2166  TE.Length01 = TempTrackElement.Length01;
2167  TE.Length23 = TempTrackElement.Length23;
2168  TE.SpeedLimit01 = TempTrackElement.SpeedLimit01;
2169  TE.SpeedLimit23 = TempTrackElement.SpeedLimit23;
2170  ErasedTrackVectorPosition = -1;
2171  }
2172  }
2173 
2174  if(ActiveElementErased && FootCrossingErased) //reinstate a basic horiz or vert element with all the same attributes [not else if... because can have a crossing and platform(s) at same location
2175  {
2176  int NewSpeedTag = 1; //horizontal
2177  if((TempTrackElement.SpeedTag == 130) || (TempTrackElement.SpeedTag == 146))
2178  {
2179  NewSpeedTag = 2; //vertical
2180  }
2181  PlotAndAddTrackElement(5, NewSpeedTag, 0, HLocInput, VLocInput, TrackPlottedFlag, false, false);
2182  //0 for Aspect indicates adding and not pasting
2183  TTrackElement &TE = GetTrackElementFromTrackMap(10, HLocInput, VLocInput);
2184  TE.SigAspect = TempTrackElement.SigAspect;
2185  TE.Length01 = TempTrackElement.Length01;
2186  TE.Length23 = TempTrackElement.Length23;
2187  TE.SpeedLimit01 = TempTrackElement.SpeedLimit01;
2188  TE.SpeedLimit23 = TempTrackElement.SpeedLimit23;
2189  ErasedTrackVectorPosition = -1;
2190  //need to update EveryPrefDir with the new SpeedTag value at H&V
2191  bool FoundFlag;
2192  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
2193  TempEveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(36, HLocInput, VLocInput, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
2194  if(PrefDirPos0 > -1)
2195  {
2196  TempEveryPrefDir->GetModifiablePrefDirElementAt(14, PrefDirPos0).SpeedTag = NewSpeedTag;
2197  }
2198  if(PrefDirPos1 > -1)
2199  {
2200  TempEveryPrefDir->GetModifiablePrefDirElementAt(15, PrefDirPos1).SpeedTag = NewSpeedTag;
2201  }
2202  if(PrefDirPos2 > -1)
2203  {
2204  TempEveryPrefDir->GetModifiablePrefDirElementAt(16, PrefDirPos2).SpeedTag = NewSpeedTag;
2205  }
2206  if(PrefDirPos3 > -1)
2207  {
2208  TempEveryPrefDir->GetModifiablePrefDirElementAt(17, PrefDirPos3).SpeedTag = NewSpeedTag;
2209  }
2210  }
2211 
2212  if(TrackEraseSuccessfulFlag)
2213  {
2214  CalcHLocMinEtc(2);
2215  SetTrackFinished(false);
2216  }
2217  if(InternalChecks)
2218  {
2219  CheckMapAndTrack(1); // test
2220  CheckMapAndInactiveTrack(1); // test
2221  CheckLocationNameMultiMap(6); // test
2222  }
2223  AllRoutes->RebuildRailwayFlag = true; //rebuild to clear any location names where named locations erased
2224  Utilities->CallLogPop(428);
2225 }
2226 
2227 // ---------------------------------------------------------------------------
2228 
2229 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
2230 // TrackPlottedFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2231 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2232 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2233 // PerformNameSearch added at v2.18.0 to speed up named element additions when area selected
2234 {
2235  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2236  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2237  bool PlatAllowedFlag = false;
2238 
2239  TrackPlottedFlag = false;
2240 /*
2241  Not erase, that covered separately.
2242  First check if Current SpeedButton assigned, then check if a platform and only
2243  permit if an appropriate trackpiece already there & not a same platform there.
2244  - can't enter a platform without track first.
2245  Then for non-platforms, check if a track piece already present at location &
2246  reject if so.
2247 */
2248 
2249  TLocationNameMultiMapEntry LocationNameEntry;
2250 
2251  LocationNameEntry.first = "";
2252  if(CurrentTag == 0)
2253  {
2254  Utilities->CallLogPop(429);
2255  return; // not assigned yet
2256  }
2257  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2258 
2259  TempTrackElement.HLoc = HLocInput;
2260  TempTrackElement.VLoc = VLocInput;
2261  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2262 // new at version 0.6 - set signal aspect depending on build mode
2263 
2264  if(TempTrackElement.TrackType == SignalPost)
2265  {
2266  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2267  // pasting a SignalPost can only have values 1 to 4
2268  {
2270  {
2271  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2272  }
2274  {
2275  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2276  }
2278  {
2279  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2280  }
2281  else
2282  {
2283  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2284  }
2285  }
2286  else if(Aspect == 1)
2287  {
2288  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2289  }
2290  else if(Aspect == 2)
2291  {
2292  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2293  }
2294  else if(Aspect == 3)
2295  {
2296  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2297  }
2298  else
2299  {
2300  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2301  }
2302  }
2303  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2304  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2305  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2306  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2307 
2308  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2309  {
2311  {
2312  NonStationOrLevelCrossingPresent = true;
2313  }
2314  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2315  {
2316  NonStationOrLevelCrossingPresent = true;
2317  }
2318  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2319  {
2320  PlatformPresent = true;
2321  }
2322  // no need to check IMPair.second since if that exists it is because .first is a platform
2323  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2324  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2325  }
2326 // check platforms
2327  if(TempTrackElement.TrackType == Platform)
2328  {
2329  if(FoundFlag) // active track element already there
2330  {
2331  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2332  {
2333  ;
2334  }
2335  // same platform type already there so above keeps PlatAllowedFlag false
2336  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2337  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2338  {
2339  PlatAllowedFlag = true;
2340  }
2341  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2342  {
2343  PlatAllowedFlag = true;
2344  }
2345  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2346  {
2347  PlatAllowedFlag = true;
2348  }
2349  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2350  {
2351  PlatAllowedFlag = true;
2352  }
2353  if(PlatAllowedFlag)
2354  {
2355  TrackPlottedFlag = true; // needed in order to call LinkTrack
2356  TrackPush(1, TempTrackElement);
2357  if(PerformNameSearch)
2358  {
2359  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2360  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2361  // Must be called AFTER TrackPush
2362  // No need to plot the element - Clearand ... called after this function called
2363  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2364  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2365  }
2366 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2367 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2368 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2369  if(InternalChecks)
2370  {
2371  CheckMapAndInactiveTrack(5); // test
2372  CheckLocationNameMultiMap(4); // test
2373  }
2374  Utilities->CallLogPop(430);
2375  return;
2376  }
2377  } // if(FoundFlag)
2378 
2379  Utilities->CallLogPop(431);
2380  return;
2381  } // if platform
2382 
2383 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2384  if(TempTrackElement.TrackType == NamedNonStationLocation)
2385  {
2386  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2387  (!FoundFlag && !InactiveFoundFlag))
2388  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2389  {
2390  TrackPlottedFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2391  TrackPush(2, TempTrackElement);
2392  if(PerformNameSearch)
2393  {
2394  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2395  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2396  }
2397  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2398  {
2399 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2400 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2401 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2402  }
2403  if(InternalChecks)
2404  {
2405  CheckMapAndInactiveTrack(11); // test
2406  CheckLocationNameMultiMap(12); // test
2407  }
2408  Utilities->CallLogPop(432);
2409  return;
2410  }
2411  else
2412  {
2413  Utilities->CallLogPop(433);
2414  return;
2415  }
2416  }
2417 // check if a level crossing - OK if placed on a plain straight track
2418  if(TempTrackElement.TrackType == LevelCrossing)
2419  {
2420  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2421  {
2422  TrackPush(11, TempTrackElement);
2423  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2424 // no need for reference to LC element as can't be open
2425  TrackPlottedFlag = true;
2426  Utilities->CallLogPop(1907);
2427  return;
2428  }
2429  else
2430  {
2431  Utilities->CallLogPop(1906);
2432  return; // was a level crossing but can't place it for some reason
2433  }
2434  }
2435 
2436 // check if another element already there
2437  else if(FoundFlag || InactiveFoundFlag)
2438  {
2439  Utilities->CallLogPop(434);
2440  return; // something already there (active or inactive track)
2441  }
2442 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2443 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2444 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2445 // do this after pushed into vector so that can use EnterLocationName
2446 
2447  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2448  {
2449  TrackPush(3, TempTrackElement);
2450  if(PerformNameSearch)
2451  {
2452  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2453  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2454  }
2455  }
2456  else if(TempTrackElement.TrackType == Points)
2457  {
2458  TrackPush(4, TempTrackElement);
2459  bool BothPointFillets = true;
2460  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2461  }
2462  else if(TempTrackElement.TrackType == SignalPost)
2463  {
2464  TrackPush(10, TempTrackElement);
2465  PlotSignal(12, TempTrackElement, Display);
2466  }
2467  else
2468  {
2469  TrackPush(5, TempTrackElement);
2470  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2471  }
2472  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2473  {
2474  TrackPlottedFlag = true; // plats & NamedLocs aleady dealt with
2475  }
2476  if(InternalChecks && PerformNameSearch) //don't carry out checks if PerformNameSearch false else will fail, should be set correctly in calling function but include to be sure
2477  {
2478  CheckMapAndTrack(2); // test
2479  CheckMapAndInactiveTrack(2); // test
2480  CheckLocationNameMultiMap(5); // test
2481  }
2482  Utilities->CallLogPop(2062);
2483 }
2484 
2485 // ---------------------------------------------------------------------------
2486 
2487 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2488  bool InternalChecks)
2489 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2490 {
2491  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2492  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2493  bool PlatAllowedFlag = false;
2494 
2495  TrackLinkingRequiredFlag = false;
2496  TLocationNameMultiMapEntry LocationNameEntry;
2497 
2498  LocationNameEntry.first = "";
2499  if(TempTrackElement.SpeedTag == 0)
2500  {
2501  Utilities->CallLogPop(2063);
2502  return; // not assigned yet
2503  }
2504  TempTrackElement.HLoc = HLocInput;
2505  TempTrackElement.VLoc = VLocInput;
2506  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2507  for(int x = 0; x < 4; x++) // unset any gaps,
2508  {
2509  if(TempTrackElement.Config[x] == Gap)
2510  {
2511  TempTrackElement.ConnLinkPos[x] = -1;
2512  }
2513  TempTrackElement.Conn[x] = -1;
2514  }
2515  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2516 // new at version 0.6 - set signal aspect depending on build mode
2517  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2518 
2519  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2520  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2521  // for the active track element because these aren't set
2522  // if don't do this then get a mismatch error during map checks later
2523 
2524  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2525 
2526  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2527  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2528 
2529  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2530  {
2531  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2532  {
2533  NonStationOrLevelCrossingPresent = true;
2534  }
2535  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2536  {
2537  NonStationOrLevelCrossingPresent = true;
2538  }
2539  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2540  {
2541  PlatformPresent = true;
2542  }
2543  // no need to check IMPair.second since if that exists it is because .first is a platform
2544  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2545  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2546  }
2547 // check platforms
2548  if(TempTrackElement.TrackType == Platform)
2549  {
2550  if(FoundFlag) // active track element already there
2551  {
2552  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2553  {
2554  ;
2555  }
2556  // same platform type already there so above keeps PlatAllowedFlag false
2557  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2558  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2559  {
2560  PlatAllowedFlag = true;
2561  }
2562  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2563  {
2564  PlatAllowedFlag = true;
2565  }
2566  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2567  {
2568  PlatAllowedFlag = true;
2569  }
2570  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2571  {
2572  PlatAllowedFlag = true;
2573  }
2574  if(PlatAllowedFlag)
2575  {
2576  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2577  TrackPush(12, TempTrackElement);
2578 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2579  {
2580  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2581  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2582  }
2583  // Must be called AFTER TrackPush
2584 // No need to plot the element - Clearand ... called after this function called
2585  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2586  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2587 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2588 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2589 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2590  if(InternalChecks)
2591  {
2592  CheckMapAndInactiveTrack(12); // test
2593  CheckLocationNameMultiMap(20); // test
2594  }
2595  Utilities->CallLogPop(2064);
2596  return;
2597  }
2598  } // if(FoundFlag)
2599 
2600  Utilities->CallLogPop(2065);
2601  return;
2602  } // if platform
2603 
2604 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2605  if(TempTrackElement.TrackType == NamedNonStationLocation)
2606  {
2607  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2608  (!FoundFlag && !InactiveFoundFlag))
2609  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2610  {
2611  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2612  TrackPush(13, TempTrackElement);
2613 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2614  {
2615  {
2616  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2617  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2618  }
2619  }
2620  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2621  {
2622 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2623 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2624 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2625  }
2626  if(InternalChecks)
2627  {
2628  CheckMapAndInactiveTrack(13); // test
2629  CheckLocationNameMultiMap(21); // test
2630  }
2631  Utilities->CallLogPop(2066);
2632  return;
2633  }
2634  else
2635  {
2636  Utilities->CallLogPop(2067);
2637  return;
2638  }
2639  }
2640 // check if a level crossing - OK if placed on a plain straight track
2641  if(TempTrackElement.TrackType == LevelCrossing)
2642  {
2643  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2644  {
2645  TrackPush(14, TempTrackElement);
2646  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2647 // no need for reference to LC element as can't be open
2648  TrackLinkingRequiredFlag = true;
2649  Utilities->CallLogPop(2068);
2650  return;
2651  }
2652  else
2653  {
2654  Utilities->CallLogPop(2069);
2655  return; // was a level crossing but can't place it for some reason
2656  }
2657  }
2658 
2659 // check if another element already there
2660  else if(FoundFlag || InactiveFoundFlag)
2661  {
2662  Utilities->CallLogPop(2070);
2663  return; // something already there (active or inactive track)
2664  }
2665 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2666 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2667 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2668 // do this after pushed into vector so that can use EnterLocationName
2669 
2670  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2671  {
2672  TrackPush(15, TempTrackElement);
2673  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2674  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2675  }
2676  else if(TempTrackElement.TrackType == Points)
2677  {
2678  TrackPush(16, TempTrackElement);
2679  bool BothPointFillets = true;
2680  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2681  }
2682  else if(TempTrackElement.TrackType == SignalPost)
2683  {
2684  TrackPush(17, TempTrackElement);
2685  PlotSignal(14, TempTrackElement, Display);
2686  }
2687  else
2688  {
2689  TrackPush(18, TempTrackElement);
2690  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2691  }
2692  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2693  {
2694  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2695  }
2696  if(InternalChecks)
2697  {
2698  CheckMapAndTrack(12); // test
2699  CheckMapAndInactiveTrack(14); // test
2700  CheckLocationNameMultiMap(22); // test
2701  }
2702  Utilities->CallLogPop(2071);
2703 }
2704 
2705 // ---------------------------------------------------------------------------
2706 
2707 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2708 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2709 // return bool = true for success
2710 // LocError = true for location error & HLoc & VLoc to be inverted
2711 {
2712  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2713  LocError = false;
2714  SetTrackFinished(false);
2715  if(TrackVector.size() == 0)
2716  {
2717  Utilities->CallLogPop(437);
2718  return(false);
2719  }
2720  if(GapsUnset(7))
2721  {
2722  if(GiveMessages)
2723  {
2724  ShowMessage("Gaps must be set before track can be validated");
2725  }
2726  Utilities->CallLogPop(1135);
2727  return(false);
2728  }
2729 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2730 // returns true for any unset gaps
2732  {
2733  // can keep this exception as protected by the GapsUnset call above
2734  throw Exception("Error, gaps unset when TryToConnectTrack called");
2735  }
2737  CheckGapMap(1); // test
2738 // Gap connections now securely defined
2739 
2740  CheckMapAndTrack(8); // test
2741 
2742 // Perform a pre-check prior to TrackMap being compiled
2743  if(GiveMessages)
2744  {
2745  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2746  {
2747  Utilities->CallLogPop(439);
2748  return(false);
2749  }
2750  }
2751  else
2752  {
2753  if(!LinkTrackNoMessages(1, false))
2754  {
2755  Utilities->CallLogPop(1131);
2756  return(false);
2757  }
2758  }
2759 // here if pre-check successful
2760  if(!RepositionAndMapTrack(0))
2761  {
2762  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2763  Utilities->CallLogPop(1138);
2764  return(false);
2765  }
2766 // now perform the final assembly - FinalCall = true
2767  if(GiveMessages)
2768  {
2769  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2770  {
2771  Utilities->CallLogPop(1116);
2772  return(false);
2773  }
2774  }
2775  else
2776  {
2777  if(!LinkTrackNoMessages(2, true))
2778  {
2779  Utilities->CallLogPop(1132);
2780  return(false);
2781  }
2782  }
2783 // success
2784 
2785  PopulateLCVector(0);
2786  CheckGapMap(2); // test
2787  CheckMapAndTrack(3); // test
2788  CheckMapAndInactiveTrack(3); // test
2789  CheckLocationNameMultiMap(9); // test
2790  SetTrackFinished(true);
2791 
2792 // Build ContinuationNameMap
2793  std::pair<AnsiString, char>TempMapPair;
2794 
2795  ContinuationNameMap.clear();
2796  for(int x = 0; x < Track->TrackVectorSize(); x++)
2797  {
2798  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2799  {
2800  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2801  TempMapPair.second = 'x'; // unused
2802  ContinuationNameMap.insert(TempMapPair);
2803  }
2804  }
2805 
2806 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2807 //(don't report blue areas without track as these unlikely to be mistakes)
2808 
2809  if(TrackFinished)
2810  {
2811  AnsiString Name = "";
2812  typedef std::list<AnsiString> TNoPlatsList;
2813  TNoPlatsList::iterator NPLIt;
2814  TNoPlatsList NoPlatsList;
2815  typedef std::list<AnsiString> TLocNameList;
2816  TLocNameList LocNameList; //single entry for each name
2819  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2820  {
2821  LocNameList.push_back(LNMMIt->first);
2822  }
2823  LocNameList.sort();
2824  LocNameList.unique();
2825  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2826  {
2827  Name = *LNLIt;
2828  MMRange = LocationNameMultiMap.equal_range(Name);
2829  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2830  {
2831  continue;
2832  }
2833  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2834  {
2835  if((LNMMIt->second) < 0) //active track element
2836  {
2837  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2838  {
2839  break;
2840  }
2841  }
2842  else //inactive
2843  {
2844  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2845  {
2846  break;
2847  }
2848  }
2849  TempIt = MMRange.second;
2850  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2851  {
2852  NoPlatsList.push_back(Name);
2853  }
2854  }
2855  }
2856  if(!NoPlatsList.empty())
2857  {
2858  AnsiString NoPlatsAnsiList = "";
2859  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2860  {
2861  NoPlatsAnsiList += *NPLIt + '\n';
2862  }
2864  {
2865  if(NoPlatsList.size() > 1)
2866  {
2867  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2868  }
2869  else
2870  {
2871  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2872  }
2873  Utilities->NoPlatsMessageSent = true;
2874  }
2875  }
2876  }
2877  Utilities->CallLogPop(440);
2878  return(true);
2879 }
2880 
2881 // ---------------------------------------------------------------------------
2882 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2883 // unused - too time-consuming - double brute force search
2884 {
2885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2886  int NewHLoc, NewVLoc;
2887  bool ConnectionFoundFlag, LinkFoundFlag;
2888 
2889  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2890  {
2891  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2892  {
2893  if(TrackElementAt(1061, x).Link[y] <= 0)
2894  {
2895  continue; // no link
2896  }
2897  if(TrackElementAt(1062, x).Config[y] == End)
2898  {
2899  continue; // buffer or continuation
2900  }
2901  if(TrackElementAt(1063, x).Config[y] == Gap)
2902  {
2903  continue; // gap jump
2904  }
2905  // get required H & V for track element joining link 'y'
2906  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2907  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2908  // find track element if present
2909  ConnectionFoundFlag = false;
2910  for(unsigned int z = 0; z < TrackVector.size(); z++)
2911  {
2912 // if(TrackElementAt(5, z).TrackType == Platform)
2913 // continue; //skip platforms
2914  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2915  {
2916  ConnectionFoundFlag = true;
2917  // find connecting link in the newly found track element if there is one
2918  LinkFoundFlag = false;
2919  for(unsigned int a = 0; a < 4; a++)
2920  {
2921  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2922  {
2923  LinkFoundFlag = true;
2924  }
2925  }
2926  // if there isn't a corresponding link set the invert values for the offending element
2927  if(!LinkFoundFlag)
2928  {
2929  HLoc = TrackElementAt(1072, x).HLoc;
2930  VLoc = TrackElementAt(1073, x).VLoc;
2931  Utilities->CallLogPop(441);
2932  return(true);
2933  }
2934  break; // success, so break out of 'z' loop
2935  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2936 
2937  } // for z...
2938  // if there isn't a connection set the invert values for the offending element
2939  if(!ConnectionFoundFlag)
2940  {
2941  HLoc = TrackElementAt(1074, x).HLoc;
2942  VLoc = TrackElementAt(1075, x).VLoc;
2943  Utilities->CallLogPop(442);
2944  return(true);
2945  }
2946  } // for y....
2947  } // for x...
2948  Utilities->CallLogPop(443);
2949  return(false); // all OK
2950 }
2951 
2952 // ---------------------------------------------------------------------------
2953 
2954 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2955 {
2956  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2957  TrackElement.LogTrack(0));
2958  bool FoundFlag;
2959 
2960  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2961  if(FoundFlag)
2962  {
2963  TrackElement = TrackElementAt(1076, Position);
2964  }
2965  Utilities->CallLogPop(444);
2966  return(FoundFlag);
2967 }
2968 
2969 // ---------------------------------------------------------------------------
2970 
2972 {
2973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2974  if(NextTrackElementPtr >= TrackVector.end())
2975  {
2976  Utilities->CallLogPop(1336);
2977  return(false);
2978  }
2979  Next = *NextTrackElementPtr;
2981  Utilities->CallLogPop(1337);
2982  return(true);
2983 }
2984 
2985 // ---------------------------------------------------------------------------
2986 
2988 {
2989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2991  {
2992  Utilities->CallLogPop(1338);
2993  return(false);
2994  }
2995  Next = *NextTrackElementPtr;
2997  Utilities->CallLogPop(1339);
2998  return(true);
2999 }
3000 
3001 // ---------------------------------------------------------------------------
3002 
3003 int TTrack::NumberOfGaps(int Caller)
3004 
3005 {
3006  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
3007  int Count = 0;
3008 
3009  if(TrackVector.size() == 0)
3010  {
3011  Utilities->CallLogPop(1340);
3012  return(0);
3013  }
3014  for(unsigned int x = 0; x < TrackVector.size(); x++)
3015  {
3016  if(TrackElementAt(1077, x).TrackType == GapJump)
3017  {
3018  Count++;
3019  }
3020  }
3021  Utilities->CallLogPop(1341);
3022  return(Count);
3023 }
3024 
3025 // ---------------------------------------------------------------------------
3027 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
3028 // returns true for any unset gaps
3029 {
3030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
3031  bool UnsetGaps = false;
3032 
3033  if(TrackVector.size() == 0)
3034  {
3035  Utilities->CallLogPop(445);
3036  return(false);
3037  }
3038  for(unsigned int x = 0; x < TrackVector.size(); x++)
3039  {
3040  if(TrackElementAt(1078, x).TrackType != GapJump)
3041  {
3042  for(unsigned int y = 0; y < 4; y++)
3043  {
3044  TrackElementAt(1079, x).Conn[y] = -1;
3045  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
3046  }
3047  }
3048  else // GapJump
3049  {
3050 // int tempint = TrackElementAt(, x).Conn[0);
3051 
3052  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
3053  {
3054  for(unsigned int y = 0; y < 4; y++)
3055  {
3056  TrackElementAt(1082, x).Conn[y] = -1;
3057  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
3058  }
3059  UnsetGaps = true;
3060  continue; // to next 'x'
3061  }
3062  else // set, but may not have matching element, or that element may not be set
3063  {
3064  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
3065  {
3066  TrackElementAt(1084, x).Conn[y] = -1;
3067  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
3068  }
3069 
3070  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
3071  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
3072  {
3073  for(unsigned int y = 0; y < 4; y++)
3074  {
3075  TrackElementAt(1087, x).Conn[y] = -1;
3076  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
3077  }
3078  UnsetGaps = true;
3079  continue; // to next 'x'
3080  }
3081 // here if gap connection is itself a GapJump
3082  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
3083  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
3084  // if not clear Conns & CLks & reset Lk[0]
3085  {
3086  for(unsigned int y = 0; y < 4; y++)
3087  {
3088  TrackElementAt(1090, x).Conn[y] = -1;
3089  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
3090  }
3091  UnsetGaps = true;
3092  continue; // to next 'x'
3093  }
3094 // here if gap connection itself points back to 'x' so these two GapJumps match properly
3095 // hence no more action needed on these Conns & CLks
3096  }
3097  } // else //gap jump
3098 
3099  } // for x...
3100  Utilities->CallLogPop(446);
3101  return(UnsetGaps);
3102 }
3103 
3104 // ---------------------------------------------------------------------------
3105 
3106 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
3107 {
3108 // VecFile already open and its pointer at right place on calling
3109  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
3110  int TempInt;
3111 
3112  TrackClear(1);
3113 // load track elements
3114  int NumberOfActiveElements = 0;
3115 
3116  GraphicsFollow = false;
3117  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3118  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
3119 
3120  if(MarkerString[MarkerString.Length()] == '1')
3121  {
3122  GraphicsFollow = true;
3123  }
3124  for(int x = 0; x < NumberOfActiveElements; x++)
3125  {
3126  VecFile >> TempInt; // TrackVectorNumber, not used
3127  VecFile >> TempInt; // SpeedTag
3128  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3129  VecFile >> TempInt;
3130  TrackElement.HLoc = TempInt;
3131  VecFile >> TempInt;
3132  TrackElement.VLoc = TempInt;
3133  if(TrackElement.TrackType == GapJump)
3134  {
3135  VecFile >> TempInt;
3136  TrackElement.ConnLinkPos[0] = TempInt;
3137  VecFile >> TempInt;
3138  TrackElement.Conn[0] = TempInt;
3139  }
3140  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3141  {
3142  VecFile >> TempInt;
3143  TrackElement.Attribute = TempInt;
3144  }
3145  if(TrackElement.TrackType == SignalPost)
3146  {
3147  VecFile >> TempInt;
3148  if(TempInt == 0)
3149  {
3150  TrackElement.CallingOnSet = false;
3151  }
3152  else
3153  {
3154  TrackElement.CallingOnSet = true;
3155  }
3156  }
3157  VecFile >> TempInt;
3158  TrackElement.Length01 = TempInt;
3159  VecFile >> TempInt;
3160  TrackElement.Length23 = TempInt;
3161  VecFile >> TempInt;
3162  if((TempInt != -1) && (TempInt < 10))
3163  {
3164  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3165  }
3166  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3167  {
3168  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3169  }
3170  TrackElement.SpeedLimit01 = TempInt;
3171  VecFile >> TempInt;
3172  if((TempInt != -1) && (TempInt < 10))
3173  {
3174  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3175  }
3176  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3177  {
3178  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3179  }
3180  TrackElement.SpeedLimit23 = TempInt;
3181 
3182  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3183  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3184  SetElementID(0, TrackElement);
3185  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3186 // new for v0.6
3187  if(TrackElement.TrackType == SignalPost)
3188  {
3189  if(Marker[1] == '3')
3190  {
3191  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3192  }
3193  else if(Marker[1] == '2')
3194  {
3195  TrackElement.SigAspect = TTrackElement::TwoAspect;
3196  }
3197  else if(Marker[1] == 'G')
3198  {
3199  TrackElement.SigAspect = TTrackElement::GroundSignal;
3200  }
3201  else
3202  {
3203  TrackElement.SigAspect = TTrackElement::FourAspect;
3204  }
3205  }
3206  if(TrackElement.SpeedTag != 0)
3207  {
3208  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3209  }
3210  }
3211  int NumberOfInactiveElements = 0;
3212 
3213  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3214  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3215  for(int x = 0; x < NumberOfInactiveElements; x++)
3216  {
3217  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3218  VecFile >> TempInt; // SpeedTag
3219  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3220  VecFile >> TempInt;
3221  TrackElement.HLoc = TempInt;
3222  VecFile >> TempInt;
3223  TrackElement.VLoc = TempInt;
3224  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3225  SetElementID(3, TrackElement);
3226  TrackPush(9, TrackElement);
3227  Utilities->LoadFileString(VecFile); // marker
3228  }
3229  bool LocError = false; // needed for TryToConnectTrack but not used
3230  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3231 
3232  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3233  {
3234  SetTrackFinished(true);
3235  }
3236  else
3237  {
3238  SetTrackFinished(false);
3239  }
3240 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3241 // CheckMapAndInactiveTrack(8);
3242 // CheckLocationNameMultiMap(10);
3243  Utilities->CallLogPop(448);
3244 }
3245 
3246 // ---------------------------------------------------------------------------
3247 
3248 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3249 {
3250 // VecFile already open and its pointer at right place on calling
3251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3252 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3253 // & load into UserGraphicItem then store in UserGraphicVector
3254  UserGraphicVector.clear();
3255  TUserGraphicItem UGI;
3256  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3257 
3258  for(int x = 0; x < NumberOfGraphics; x++)
3259  {
3260  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3261  UGI.HPos = Utilities->LoadFileInt(VecFile);
3262  UGI.VPos = Utilities->LoadFileInt(VecFile);
3263  UGI.Width = 0; // provisional value
3264  UGI.Height = 0; // provisional value
3265  UGI.UserGraphic = NULL; // provisional value
3266  UserGraphicVector.push_back(UGI);
3267  }
3268 // now load the map & set Width, Height & TPicture*
3269  bool FileError = false;
3270 
3271  for(int x = 0; x < NumberOfGraphics; x++)
3272  {
3273  if(FileError)
3274  {
3275  break; // otherwise keeps going round the loop
3276  }
3277  UGI = UserGraphicVectorAt(0, x);
3278  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3279  {
3280  try
3281  {
3282 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3283  UGME.first = UGI.FileName;
3284  UGME.second = new TPicture;
3285  UGME.second->LoadFromFile(UGME.first); // errors caught below
3286  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3287  {
3288  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3289  }
3290  UGI.UserGraphic = UGME.second;
3291  UGI.Width = UGI.UserGraphic->Width;
3292  UGI.Height = UGI.UserGraphic->Height;
3293  UserGraphicVectorAt(1, x) = UGI;
3294  }
3295  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3296  {
3297  //message already sent in CheckUserGraphics
3298  FileError = true;
3299  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3300  if(!UserGraphicMap.empty())
3301  {
3302  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3303  {
3304  delete UGMIt->second;
3305  }
3306  UserGraphicMap.clear();
3307  }
3308  }
3309  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3310  {
3311  //message already sent in CheckUserGraphics
3312  FileError = true;
3313  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3314  if(!UserGraphicMap.empty())
3315  {
3316  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3317  {
3318  delete UGMIt->second;
3319  }
3320  UserGraphicMap.clear();
3321  }
3322  }
3323  }
3324  else
3325  {
3326  bool FoundInMap = false;
3327  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3328  {
3329  if(UGI.FileName == UGMIt->first) // already exists in map
3330  {
3331  UGI.UserGraphic = UGMIt->second;
3332  UGI.Width = UGI.UserGraphic->Width;
3333  UGI.Height = UGI.UserGraphic->Height;
3334  UserGraphicVectorAt(2, x) = UGI;
3335  FoundInMap = true;
3336  break;
3337  }
3338  }
3339  if(!FoundInMap)
3340  {
3341  try
3342  {
3344  UGME.first = UGI.FileName;
3345  UGME.second = new TPicture;
3346  UGME.second->LoadFromFile(UGME.first); // errors caught below
3347  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3348  {
3349  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3350  }
3351  UGI.UserGraphic = UGME.second;
3352  UGI.Width = UGI.UserGraphic->Width;
3353  UGI.Height = UGI.UserGraphic->Height;
3354  UserGraphicVectorAt(3, x) = UGI;
3355  }
3356  catch(const EInvalidGraphic &e) //non error catch - CallLogPop called at end of function
3357  {
3358  //message already sent in CheckUserGraphics
3359  FileError = true;
3360  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3361  if(!UserGraphicMap.empty())
3362  {
3363  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3364  {
3365  delete UGMIt->second;
3366  }
3367  UserGraphicMap.clear();
3368  }
3369  }
3370  catch(const Exception &e) //non error catch - CallLogPop called at end of function
3371  {
3372  //message already sent in CheckUserGraphics
3373  FileError = true;
3374  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3375  if(!UserGraphicMap.empty())
3376  {
3377  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3378  {
3379  delete UGMIt->second;
3380  }
3381  UserGraphicMap.clear();
3382  }
3383  }
3384  }
3385  }
3386  }
3387  Utilities->CallLogPop(2167);
3388 }
3389 
3390 // ---------------------------------------------------------------------------
3391 
3392 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3393 {
3394 // VecFile already open and its pointer at right place on calling
3395 // if GraphicsFollow true, then save Marker as **Active elements**1
3396 // save trackfinished flag
3397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3398  TTrackElement TrackElement, InactiveTrackElement;
3399 
3400 // save track elements
3401  Utilities->SaveFileInt(VecFile, TrackVector.size());
3402  if(GraphicsFollow)
3403  {
3404  VecFile << "**Active elements**1" << '\0' << '\n';
3405  }
3406  else
3407  {
3408  VecFile << "**Active elements**" << '\0' << '\n';
3409  }
3410  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3411  {
3412  TrackElement = TrackElementAt(1092, x);
3413  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3414  VecFile << TrackElement.SpeedTag << '\n';
3415  VecFile << TrackElement.HLoc << '\n';
3416  VecFile << TrackElement.VLoc << '\n';
3417  if(TrackElement.TrackType == GapJump)
3418  {
3419  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3420  VecFile << TrackElement.Conn[0] << '\n';
3421  }
3422  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3423  {
3424  VecFile << TrackElement.Attribute << '\n';
3425  }
3426  if(TrackElement.TrackType == SignalPost)
3427  {
3428  if(TrackElement.CallingOnSet)
3429  {
3430  VecFile << int(1) << '\n';
3431  }
3432  else
3433  {
3434  VecFile << int(0) << '\n';
3435  }
3436  }
3437  VecFile << TrackElement.Length01 << '\n';
3438  VecFile << TrackElement.Length23 << '\n';
3439  VecFile << TrackElement.SpeedLimit01 << '\n';
3440  VecFile << TrackElement.SpeedLimit23 << '\n';
3441  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3442  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3443 // new for v0.6
3444  if(TrackElement.TrackType == SignalPost)
3445  {
3446  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3447  {
3448  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3449  }
3450  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3451  {
3452  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3453  }
3454  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3455  {
3456  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3457  }
3458  else // 4 aspect
3459  {
3460  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3461  }
3462  }
3463  else
3464  {
3465  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3466  }
3467  }
3468 
3469  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3470  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3471  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3472  {
3473  InactiveTrackElement = InactiveTrackElementAt(136, x);
3474  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3475  VecFile << InactiveTrackElement.SpeedTag << '\n';
3476  VecFile << InactiveTrackElement.HLoc << '\n';
3477  VecFile << InactiveTrackElement.VLoc << '\n';
3478  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3479  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3480  }
3481  Utilities->CallLogPop(449);
3482 }
3483 
3484 // ---------------------------------------------------------------------------
3485 
3486 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3487 {
3488 // VecFile already open and its pointer at right place on calling
3489 // check trackfinished flag
3490 // inactive elements follow immediately after active elements, no need to check for a marker between them
3491  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3492  int TempInt;
3493 
3494  GraphicsFollow = false;
3495  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3496  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3497  {
3498  Utilities->CallLogPop(1513);
3499  return(false);
3500  }
3501 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3502  AnsiString MarkerString;
3503 
3504  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3505  {
3506  Utilities->CallLogPop(1758);
3507  return(false);
3508  }
3509  if(MarkerString[MarkerString.Length()] == '1')
3510  {
3511  GraphicsFollow = true;
3512  }
3513  for(int x = 0; x < NumberOfActiveElements; x++)
3514  {
3515  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3516  {
3517  Utilities->CallLogPop(1759);
3518  return(false);
3519  }
3520  VecFile >> TempInt;
3521  int SpeedTag = TempInt;
3522  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3523  {
3524  Utilities->CallLogPop(1514);
3525  return(false);
3526  }
3527  VecFile >> TempInt;
3528  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3529  {
3530  Utilities->CallLogPop(1495);
3531  return(false);
3532  }
3533  VecFile >> TempInt;
3534  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3535  {
3536  Utilities->CallLogPop(1497);
3537  return(false);
3538  }
3539  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3540  {
3541  VecFile >> TempInt;
3542  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3543  {
3544  Utilities->CallLogPop(1499);
3545  return(false);
3546  }
3547  VecFile >> TempInt;
3548  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3549  {
3550  Utilities->CallLogPop(1500);
3551  return(false);
3552  }
3553  }
3554  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3555  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3556  {
3557  VecFile >> TempInt;
3558  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3559  {
3560  Utilities->CallLogPop(1502);
3561  return(false);
3562  }
3563  }
3564  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3565  {
3566  VecFile >> TempInt;
3567  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3568  {
3569  Utilities->CallLogPop(1155);
3570  return(false);
3571  }
3572  }
3573  VecFile >> TempInt;
3574  if((TempInt < -1) || (TempInt > 999999)) // Length01
3575  {
3576  Utilities->CallLogPop(1503);
3577  return(false);
3578  }
3579  VecFile >> TempInt;
3580  if((TempInt < -1) || (TempInt > 999999)) // Length23
3581  {
3582  Utilities->CallLogPop(1504);
3583  return(false);
3584  }
3585  VecFile >> TempInt;
3586  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3587  {
3588  Utilities->CallLogPop(1505);
3589  return(false);
3590  }
3591  VecFile >> TempInt;
3592  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3593  {
3594  Utilities->CallLogPop(1506);
3595  return(false);
3596  }
3597  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3598  {
3599  Utilities->CallLogPop(1142);
3600  return(false); // LocationName
3601  }
3602  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3603  {
3604  Utilities->CallLogPop(1143);
3605  return(false); // ActiveTrackElementName
3606  }
3607  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3608  {
3609  Utilities->CallLogPop(1787);
3610  return(false); // marker
3611  }
3612  }
3613  int NumberOfInactiveElements = 0;
3614 
3615  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3616  if(NumberOfInactiveElements < 0) // No of active elements
3617  {
3618  Utilities->CallLogPop(1493);
3619  return(false);
3620  }
3621  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3622  {
3623  Utilities->CallLogPop(1764);
3624  return(false); // **Inactive elements** marker
3625  }
3626  for(int x = 0; x < NumberOfInactiveElements; x++)
3627  {
3628  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3629  {
3630  Utilities->CallLogPop(1765);
3631  return(false);
3632  }
3633  VecFile >> TempInt;
3634  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3635  {
3636  Utilities->CallLogPop(1494);
3637  return(false);
3638  }
3639  VecFile >> TempInt;
3640  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3641  {
3642  Utilities->CallLogPop(1496);
3643  return(false);
3644  }
3645  VecFile >> TempInt;
3646  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3647  {
3648  Utilities->CallLogPop(1498);
3649  return(false);
3650  }
3651  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3652  {
3653  Utilities->CallLogPop(1144);
3654  return(false); // LocationName
3655  }
3656  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3657  {
3658  Utilities->CallLogPop(1788);
3659  return(false); // marker
3660  }
3661  }
3662  Utilities->CallLogPop(1507);
3663  return(true);
3664 }
3665 
3666 // ---------------------------------------------------------------------------
3667 
3668 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3669 {
3670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3671  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3672 
3673  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3674  {
3675  Utilities->CallLogPop(2168);
3676  return(false);
3677  }
3678  // filename in Graphics folder, then HPos, then VPos
3679  AnsiString FileName = "", TempStr = "";
3680 
3681  for(int x = 0; x < NumberOfGraphics; x++)
3682  {
3683  TPicture *TempPicture = new TPicture;
3684  try
3685  {
3686  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3687  {
3688  Utilities->CallLogPop(2169);
3689  delete TempPicture;
3690  return(false);
3691  }
3692  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3693  delete TempPicture;
3694  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3695  {
3696  Utilities->CallLogPop(2170);
3697  return(false);
3698  }
3699  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3700  {
3701  Utilities->CallLogPop(2171);
3702  return(false);
3703  }
3704  }
3705  catch(const EInvalidGraphic &e) //non error catch
3706  {
3707  //move file pointer to end of graphic section for later checks in session files
3708  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3709  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3710  for(int y = x + 1; y < NumberOfGraphics; y++)
3711  {
3712  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3713  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3714  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3715  }
3716  ShowMessage(FileName +
3717  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3718  Utilities->CallLogPop(2172);
3719  delete TempPicture;
3720  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3721  }
3722  catch(const Exception &e) //non error catch
3723  {
3724  //move file pointer to end of graphic section for later checks in session files
3725  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3726  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3727  for(int y = x + 1; y < NumberOfGraphics; y++)
3728  {
3729  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3730  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3731  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3732  }
3733  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3734  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3735  Utilities->CallLogPop(2173);
3736  delete TempPicture;
3737  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3738  }
3739  }
3740  Utilities->CallLogPop(2174);
3741  return(true);
3742 }
3743 
3744 // ---------------------------------------------------------------------------
3745 
3746 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3747 {
3748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3749  int VecSize = Track->BarriersDownVector.size();
3750 
3751  Utilities->SaveFileInt(OutFile, VecSize);
3752  for(int x = 0; x < VecSize; x++)
3753  {
3755  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3756  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3757  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3758  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3759  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3760  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3761  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3762  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3763  }
3764  Utilities->CallLogPop(1963);
3765 }
3766 
3767 // ---------------------------------------------------------------------------
3768 
3769 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3770 {
3771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3772  int VecSize = Track->ChangingLCVector.size();
3773 
3774  Utilities->SaveFileInt(OutFile, VecSize);
3775  for(int x = 0; x < VecSize; x++)
3776  {
3778  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3779  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3780  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3781  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3782  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3783  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3784  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3785  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3786  }
3787  Utilities->CallLogPop(1980);
3788 }
3789 
3790 // ---------------------------------------------------------------------------
3791 
3792 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3793 {
3794  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3795  int VecSize = Utilities->LoadFileInt(VecFile);
3796 
3797  for(int x = 0; x < VecSize; x++)
3798  {
3799  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3800  {
3801  Utilities->CallLogPop(1970);
3802  return(false);
3803  }
3804  if(!Utilities->CheckFileBool(VecFile))
3805  {
3806  Utilities->CallLogPop(1971);
3807  return(false);
3808  }
3809  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3810  {
3811  Utilities->CallLogPop(1972);
3812  return(false);
3813  }
3814  if(!Utilities->CheckFileDouble(VecFile))
3815  {
3816  Utilities->CallLogPop(1973);
3817  return(false);
3818  }
3819  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3820  {
3821  Utilities->CallLogPop(1974);
3822  return(false);
3823  }
3824  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3825  {
3826  Utilities->CallLogPop(1975);
3827  return(false);
3828  }
3829  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3830  {
3831  Utilities->CallLogPop(1976);
3832  return(false);
3833  }
3834  if(!Utilities->CheckFileDouble(VecFile))
3835  {
3836  Utilities->CallLogPop(1977);
3837  return(false);
3838  }
3839  }
3840  Utilities->CallLogPop(1978);
3841  return(true);
3842 }
3843 
3844 // ---------------------------------------------------------------------------
3845 
3846 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3847 {
3848  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3849  int VecSize = Utilities->LoadFileInt(VecFile);
3850 
3851  for(int x = 0; x < VecSize; x++)
3852  {
3853  TActiveLevelCrossing TALC;
3854  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3855  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3856  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3857  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3858  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3859  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3860  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3861  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3862  BarriersDownVector.push_back(TALC);
3863  }
3864  Utilities->CallLogPop(1979);
3865 }
3866 
3867 // ---------------------------------------------------------------------------
3868 
3869 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3870 /*
3871  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3872  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3873  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3874 */
3875 {
3876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3877  TTrackElement Next;
3878 
3879  Track->RebuildUserGraphics(0, HiddenDisplay); //moved here from Clearand... so user graphics overwrites LongServRef names
3881  while(ReturnNextInactiveTrackElement(0, Next))
3882  {
3883  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3884  {
3885  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3886  {
3887  // only plot if on screen, to save time (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3888  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3889  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3890  {
3891  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3892  }
3893  }
3894  }
3895  }
3896 
3897  NextTrackElementPtr = TrackVector.begin();
3898  while(ReturnNextTrackElement(0, Next))
3899  {
3900  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3901  {
3902  // only plot if on screen, to save time (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3903  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3904  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3905  {
3906  if(Next.TrackType == Points)
3907  {
3908  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3910  {
3911  OneLengthOrSpeedHeatMapColour(0, Next, true, Disp); //true for 01 length
3912  OneLengthOrSpeedHeatMapColour(1, Next, false, Disp); //false for 23 length
3913  }
3914  }
3915  else if(Next.TrackType == SignalPost)
3916  {
3917  PlotSignal(9, Next, Disp);
3919  {
3920  OneLengthOrSpeedHeatMapColour(2, Next, true, Disp); //true for 01 length
3921  }
3922  }
3923  else if(Next.TrackType == GapJump)
3924  {
3925  PlotGap(0, Next, Disp);
3927  {
3928  OneLengthOrSpeedHeatMapColour(3, Next, true, Disp); //true for 01 length
3929  }
3930  }
3931  else if(Next.TrackType == Continuation) //added for multiplayer graphic overlays
3932  {
3933  PlotContinuation(0, Next, Disp);
3935  {
3936  OneLengthOrSpeedHeatMapColour(4, Next, true, Disp); //true for 01 length
3937  }
3938  }
3939  else if(Next.TrackType == Crossover || Next.TrackType == Bridge)
3940  {
3941  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3943  {
3944  OneLengthOrSpeedHeatMapColour(5, Next, true, Disp); //true for 01 length
3945  OneLengthOrSpeedHeatMapColour(6, Next, false, Disp); //false for 23 length
3946  }
3947  }
3948  else
3949  {
3950  Next.PlotVariableTrackElement(13, Disp); // for footcrossings, may be striped or not
3952  {
3953  OneLengthOrSpeedHeatMapColour(7, Next, true, Disp); //true for 01 length
3954  }
3955  }
3956  }
3957  }
3958  }
3959 
3960  if(BothPointFilletsAndBasicLCs)
3961  {
3963  while(ReturnNextInactiveTrackElement(4, Next))
3964  {
3965  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3966  {
3967  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3968  {
3969  // only plot if on screen, to save time, & OK as plotting one by one here (was commented out at v2.22.0 [not sure why] reinstated at v2.23.2)
3970  if(((Next.HLoc - Disp->DisplayOffsetH) >= 0) && ((Next.HLoc - Disp->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3971  ((Next.VLoc - Disp->DisplayOffsetV) >= 0) && ((Next.VLoc - Disp->DisplayOffsetV) < Utilities->ScreenElementHeight))
3972  {
3973  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3974  {
3975  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3976  }
3977  else
3978  {
3979  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3980  }
3981  }
3982  }
3983  }
3984  }
3985  }
3986 
3987  TextHandler->RebuildFromTextVector(1, Disp); // plot text after all else so visible over stations/track etc. //moved from above at v2.20.3
3988  Disp->Update();
3989  Utilities->CallLogPop(468);
3990 }
3991 
3992 // ---------------------------------------------------------------------------
3993 
3994 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3995 {
3996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3997  if(UserGraphicVector.empty())
3998  {
3999  Utilities->CallLogPop(2175);
4000  return;
4001  }
4002  TUserGraphicItem UGI;
4003 
4004  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4005  {
4006  UGI = UserGraphicVectorAt(4, x);
4007  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
4008  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
4009  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
4010  {
4011  Disp->PlotAndAddUserGraphic(0, UGI);
4012  }
4013  }
4014  Disp->Update();
4015  Utilities->CallLogPop(2176);
4016 }
4017 
4018 // ---------------------------------------------------------------------------
4019 
4020 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
4021 /*
4022  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4023 */
4024 {
4025  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
4026 // need to change graphics back to black on white if have a dark background
4027  TColor OldTransparentColour = Utilities->clTransparent;
4028 
4030  {
4031  Utilities->clTransparent = TColor(0xFFFFFF); // white
4034  }
4035  TTrackElement Next;
4036 
4037  Bitmap->Canvas->CopyMode = cmSrcCopy;
4039  Graphics::TBitmap *GraphicOutput;
4040 
4041  while(ReturnNextInactiveTrackElement(2, Next))
4042  {
4043  GraphicOutput = Next.GraphicPtr;
4044  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4045  {
4046  if(Next.LocationName == "") // plot as named or unnamed (striped)
4047  {
4048  // default is not striped
4049  switch(Next.SpeedTag)
4050  {
4051  case 76: // t platform
4052  GraphicOutput = RailGraphics->gl76Striped;
4053  break;
4054 
4055  case 77: // h platform
4056  GraphicOutput = RailGraphics->bm77Striped;
4057  break;
4058 
4059  case 78: // v platform
4060  GraphicOutput = RailGraphics->bm78Striped;
4061  break;
4062 
4063  case 79: // r platform
4064  GraphicOutput = RailGraphics->gl79Striped;
4065  break;
4066 
4067  case 96: // concourse
4068  GraphicOutput = RailGraphics->ConcourseStriped;
4069  break;
4070 
4071  case 129: // v footbridge
4072  GraphicOutput = RailGraphics->gl129Striped;
4073  break;
4074 
4075  case 130: // h footbridge
4076  GraphicOutput = RailGraphics->gl130Striped;
4077  break;
4078 
4079  case 131: // non-station named loc
4080  GraphicOutput = RailGraphics->bmNameStriped;
4081  break;
4082 
4083  case 145: // v underpass
4084  GraphicOutput = RailGraphics->gl145Striped;
4085  break;
4086 
4087  case 146: // h underpass
4088  GraphicOutput = RailGraphics->gl146Striped;
4089  break;
4090 
4091  default:
4092  GraphicOutput = Next.GraphicPtr;
4093  break;
4094  }
4095  }
4096  if(Next.SpeedTag == 144) // level crossing
4097  {
4098  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
4099  {
4100  GraphicOutput = RailGraphics->LCBothVer;
4101  }
4102  else
4103  {
4104  GraphicOutput = RailGraphics->LCBothHor;
4105  }
4106  }
4107  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4108  }
4109  }
4110 
4111  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
4112 
4113 
4114  NextTrackElementPtr = TrackVector.begin();
4115  while(ReturnNextTrackElement(2, Next))
4116  {
4117  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4118  {
4119  if(Next.TrackType == Points) // plot both fillets
4120  {
4121  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4122  if(Next.SpeedTag < 28)
4123  {
4124  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4126  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4128  }
4129  else if(Next.SpeedTag < 132)
4130  {
4131  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4132  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
4133  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4134  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
4135  }
4136  else
4137  {
4138  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4139  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
4140  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4141  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
4142  }
4143  }
4144  else if(Next.TrackType == GapJump) // plot as connected or unconnected
4145  {
4146  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
4147  {
4148  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4149  }
4150  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
4151  {
4152  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
4153  }
4154  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
4155  {
4156  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4157  }
4158  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
4159  {
4160  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
4161  }
4162  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
4163  {
4164  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4165  }
4166  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
4167  {
4168  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
4169  }
4170  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
4171  {
4172  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4173  }
4174  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
4175  {
4176  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
4177  }
4178  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
4179  {
4180  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4181  }
4182  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
4183  {
4184  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4185  }
4186  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4187  {
4188  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4189  }
4190  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4191  {
4192  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4193  }
4194  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4195  {
4196  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4197  }
4198  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4199  {
4200  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4201  }
4202  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4203  {
4204  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4205  }
4206  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4207  {
4208  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4209  }
4210  }
4211  // below added for version 0.6, only stop signals to be drawn
4212  else if(Next.TrackType == SignalPost)
4213  {
4214  for(int x = 0; x < 40; x++)
4215  {
4216  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4217  {
4218  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4219  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4220  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4221  int HOffset = 0;
4222  if(Next.SpeedTag > 73)
4223  {
4224  HOffset = 5;
4225  }
4226  else if(Next.SpeedTag == 71)
4227  {
4228  HOffset = 9;
4229  }
4230  int VOffset = 0;
4231  if(Next.SpeedTag == 69)
4232  {
4233  VOffset = 9;
4234  }
4235  else if(Next.SpeedTag == 72)
4236  {
4237  VOffset = 5;
4238  }
4239  else if(Next.SpeedTag == 74)
4240  {
4241  VOffset = 5;
4242  }
4243  Graphics::TBitmap *GraphicPtr;
4244  if(Next.SpeedTag > 71)
4245  {
4246  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4247  }
4248  else if(Next.SpeedTag < 70)
4249  {
4250  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4251  }
4252  else
4253  {
4254  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4255  }
4256  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4257  // plot special signal platform if present
4258  Graphics::TBitmap* SignalPlatformGraphic;
4259  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4260  {
4261  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4262  }
4263  // now plot signal (double yellow overwrites most of signal platform if present)
4264  // below amended for version 0.6
4266  {
4267  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4268  }
4269  else if(Next.SigAspect == TTrackElement::TwoAspect)
4270  {
4271  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4272  }
4273  else if(Next.SigAspect == TTrackElement::GroundSignal)
4274  {
4275  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4276  }
4277  else // 4 aspect
4278  {
4279  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4280  }
4281  break;
4282  }
4283  }
4284  }
4285  else
4286  {
4287  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4288  }
4289  }
4290  }
4291  if(OldTransparentColour != clB5G5R5)
4292  {
4293  Utilities->clTransparent = OldTransparentColour; // restore
4296  }
4297  Utilities->CallLogPop(1533);
4298 }
4299 
4300 // ---------------------------------------------------------------------------
4301 
4302 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4303 {
4304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4305  if(UserGraphicVector.empty())
4306  {
4307  Utilities->CallLogPop(2192);
4308  return;
4309  }
4310  else
4311  {
4312  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4313  {
4314  Bitmap->Canvas->CopyMode = cmSrcCopy;
4315  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4316  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4317  }
4318  }
4319  Utilities->CallLogPop(2193);
4320 }
4321 
4322 // ---------------------------------------------------------------------------
4323 
4324 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4325 /*
4326  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4327  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4328 */
4329 {
4330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4331 // need to change graphics back to black on white if have a dark background
4332  TColor OldTransparentColour = Utilities->clTransparent;
4333 
4335  {
4336  Utilities->clTransparent = TColor(0xFFFFFF); // white
4339  }
4340  TTrackElement Next;
4341 
4342  Bitmap->Canvas->CopyMode = cmSrcCopy;
4344  Graphics::TBitmap *GraphicOutput;
4345 
4346  while(ReturnNextInactiveTrackElement(3, Next))
4347  {
4348  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4349  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4350  {
4351  if(Next.SpeedTag == 144) // level crossing
4352  {
4353  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4354  if(BaseElement == 1) // hor element
4355  {
4356  if(Next.Attribute == 1) // open to trains
4357  {
4358  GraphicOutput = RailGraphics->LCBothHor;
4359  }
4360  else // plot as closed to trains if in any other state
4361  {
4362  GraphicOutput = RailGraphics->LCBothVer;
4363  }
4364  }
4365  else // vert element
4366  {
4367  if(Next.Attribute == 1) // open to trains
4368  {
4369  GraphicOutput = RailGraphics->LCBothVer;
4370  }
4371  else // plot as closed to trains if in any other state
4372  {
4373  GraphicOutput = RailGraphics->LCBothHor;
4374  }
4375  }
4376  }
4377  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4378  }
4379  }
4380 
4381  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4382 
4383  NextTrackElementPtr = TrackVector.begin();
4384  while(ReturnNextTrackElement(3, Next))
4385  {
4386  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4387  {
4388  if(Next.TrackType == Points) // plot active fillet
4389  {
4390  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4391  if(Next.SpeedTag < 28)
4392  {
4393  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4395  }
4396  else if(Next.SpeedTag < 132)
4397  {
4398  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4400  }
4401  else
4402  {
4403  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4405  }
4406  if(Next.Failed) //added at v2.13.0
4407  {
4408  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4410  }
4411 
4412  }
4413  else if(Next.TrackType == GapJump) // plot as connected
4414  {
4415  if(Next.SpeedTag == 88)
4416  {
4417  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4418  }
4419  else if(Next.SpeedTag == 89)
4420  {
4421  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4422  }
4423  else if(Next.SpeedTag == 90)
4424  {
4425  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4426  }
4427  else if(Next.SpeedTag == 91)
4428  {
4429  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4430  }
4431  else if(Next.SpeedTag == 92)
4432  {
4433  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4434  }
4435  else if(Next.SpeedTag == 93)
4436  {
4437  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4438  }
4439  else if(Next.SpeedTag == 94)
4440  {
4441  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4442  }
4443  else if(Next.SpeedTag == 95)
4444  {
4445  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4446  }
4447  }
4448  else if(Next.TrackType == SignalPost) //plot in correct colour
4449  {
4450  for(int x = 0; x < 40; x++)
4451  {
4452  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4453  {
4454  //plot blank first, then plot platform if present - (always not striped for operating railway)
4455  //note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4456  //in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4457  int HOffset = 0;
4458  if(Next.SpeedTag > 73)
4459  {
4460  HOffset = 5;
4461  }
4462  else if(Next.SpeedTag == 71)
4463  {
4464  HOffset = 9;
4465  }
4466  int VOffset = 0;
4467  if(Next.SpeedTag == 69)
4468  {
4469  VOffset = 9;
4470  }
4471  else if(Next.SpeedTag == 72)
4472  {
4473  VOffset = 5;
4474  }
4475  else if(Next.SpeedTag == 74)
4476  {
4477  VOffset = 5;
4478  }
4479  Graphics::TBitmap *GraphicPtr;
4480  if(Next.SpeedTag > 71)
4481  {
4482  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4483  }
4484  else if(Next.SpeedTag < 70)
4485  {
4486  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4487  }
4488  else
4489  {
4490  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4491  }
4492  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4493  // plot special signal platform if present
4494  Graphics::TBitmap* SignalPlatformGraphic;
4495  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4496  {
4497  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4498  }
4499  if(!Next.Failed)
4500  {
4501  // now plot signal (double yellow overwrites most of signal platform if present)
4502  // below amended for version 0.6
4504  {
4505  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4506  }
4507  else if(Next.SigAspect == TTrackElement::TwoAspect)
4508  {
4509  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4510  }
4511  else if(Next.SigAspect == TTrackElement::GroundSignal)
4512  {
4513  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4514  }
4515  else // 4 aspect
4516  {
4517  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4518  }
4519  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4520  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4521  {
4522  if(Next.SpeedTag == 68)
4523  {
4524  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4525  }
4526  if(Next.SpeedTag == 69)
4527  {
4528  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4529  }
4530  if(Next.SpeedTag == 70)
4531  {
4532  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4533  }
4534  if(Next.SpeedTag == 71)
4535  {
4536  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4537  }
4538  if(Next.SpeedTag == 72)
4539  {
4540  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4541  }
4542  if(Next.SpeedTag == 73)
4543  {
4544  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4545  }
4546  if(Next.SpeedTag == 74)
4547  {
4548  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4549  }
4550  if(Next.SpeedTag == 75)
4551  {
4552  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4553  }
4554  }
4555  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4556  {
4557  for(int x = 0; x < 40; x++)
4558  {
4559  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4560  {
4561  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4562  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4563  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4564  // plot special signal platform if present
4565  Graphics::TBitmap* SignalPlatformGraphic;
4566  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4567  {
4568  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4569  }
4570  // now plot signal
4571  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4572  break;
4573  }
4574  }
4575  }
4576  break;
4577  }
4578  else //added at v2.13.0
4579  {
4581  {
4582  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedSigTable[x % 5].SigPtr);
4583  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4584  }
4585  else
4586  {
4587  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, FailedGroundSigTable[x % 5].SigPtr);
4588  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->BlackOctagon);
4589  }
4590  break;
4591  }
4592  }
4593  }
4594  }
4595  else
4596  {
4597  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4598  if(Next.Failed) //added at v2.13.0
4599  {
4600  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4602  }
4603  }
4604  }
4605  }
4606  if(OldTransparentColour != clB5G5R5)
4607  {
4608  Utilities->clTransparent = OldTransparentColour; // restore
4611  }
4612  Utilities->CallLogPop(1701);
4613 }
4614 
4615 // ---------------------------------------------------------------------------
4616 
4617 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4618 {
4619  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4620  for(unsigned int x = 0; x < TrackVector.size(); x++)
4621  {
4622  if(TrackElementAt(1093, x).TrackType == GapJump)
4623  {
4624  if(TrackElementAt(1094, x).Conn[0] > -1)
4625  {
4626  continue; // to next 'x' value as this element has already been set
4627  }
4628  // here if identify a GapJump element not yet set
4629  GapPos = x;
4630  GapHLoc = TrackElementAt(1095, x).HLoc;
4631  GapVLoc = TrackElementAt(1096, x).VLoc;
4632  // highlight it
4634  Utilities->CallLogPop(469);
4635  return(true);
4636  }
4637  }
4638  Utilities->CallLogPop(470);
4639  return(false);
4640 }
4641 
4642 // ---------------------------------------------------------------------------
4643 
4644 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4645 {
4646  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4647  AnsiString(VLoc));
4648  int Position;
4649  TTrackElement TrackElement;
4650 
4651  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4652  {
4653  Utilities->CallLogPop(471);
4654  return(false); // not found
4655  }
4656  if(TrackElement.TrackType != GapJump)
4657  {
4658  Utilities->CallLogPop(472);
4659  return(false); // found something but not a gap
4660  }
4661  if(Position == GapPos)
4662  {
4663  Utilities->CallLogPop(473);
4664  return(false); // selected original gap
4665  }
4666  if(TrackElementAt(1097, Position).Conn[0] != -1)
4667  {
4668  Utilities->CallLogPop(474);
4669  return(false); // already selected
4670  }
4671  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4672  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4673  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4674  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4675 // now highlight the selected location
4676  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4677  Utilities->CallLogPop(475);
4678  return(true);
4679 }
4680 
4681 // ---------------------------------------------------------------------------
4682 
4683 bool TTrack::GapsUnset(int Caller)
4684 // returns true if there are gaps and any are unset
4685 {
4686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4687  if(TrackVector.size() == 0)
4688  {
4689  Utilities->CallLogPop(476);
4690  return(false);
4691  }
4692  for(unsigned int x = 0; x < TrackVector.size(); x++)
4693  {
4694  if(TrackElementAt(1102, x).TrackType == GapJump)
4695  {
4696  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4697  {
4698  Utilities->CallLogPop(477);
4699  return(true);
4700  }
4701  else // set, but may not have matching element, or that element may not be set
4702  {
4703  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4704  // check that the element pointed to by the gap link is a GapJump
4705  {
4706  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4707  Utilities->CallLogPop(1137);
4708  return(false);
4709  }
4710 // here if gap connection is itself a GapJump
4711  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4712  // check that the element pointed to by the gap link is a GapJump & that its gap link
4713  // points back to 'x'
4714  {
4715  Utilities->CallLogPop(478);
4716  return(true);
4717  }
4718 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4719  }
4720  } // if(TrackElementAt(, x).TrackType == GapJump)
4721 
4722  } // for x...
4723  Utilities->CallLogPop(479);
4724  return(false);
4725 }
4726 
4727 // ---------------------------------------------------------------------------
4728 
4729 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4730 {
4731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4732  for(unsigned int x = 0; x < TrackVector.size(); x++)
4733  {
4734  if(TrackElementAt(1110, x).TrackType == GapJump)
4735  {
4736  Utilities->CallLogPop(1105);
4737  return(false);
4738  }
4739  }
4740  Utilities->CallLogPop(1106);
4741  return(true);
4742 }
4743 
4744 // ---------------------------------------------------------------------------
4745 
4746 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4747 {
4748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4749  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4750  {
4751  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4752  {
4753  Utilities->CallLogPop(1107);
4754  return(false);
4755  }
4756  }
4757  for(unsigned int x = 0; x < TrackVector.size(); x++)
4758  {
4759  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4760  {
4761  Utilities->CallLogPop(1108);
4762  return(false);
4763  }
4764  }
4765  Utilities->CallLogPop(1109);
4766  return(true);
4767 }
4768 
4769 // ---------------------------------------------------------------------------
4770 
4772 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4773 // returns false otherwise or if there are no NamedLocationElements
4774 {
4775  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4776  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4777  {
4778  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4779  {
4780  if(InactiveTrackElementAt(139, x).LocationName == "")
4781  {
4782  Utilities->CallLogPop(1110);
4783  return(true);
4784  }
4785  }
4786  }
4787  for(unsigned int x = 0; x < TrackVector.size(); x++)
4788  {
4789  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4790  {
4791  if(TrackElementAt(1113, x).LocationName == "")
4792  {
4793  Utilities->CallLogPop(1111);
4794  return(true);
4795  }
4796  }
4797  }
4798  Utilities->CallLogPop(1112);
4799  return(false);
4800 }
4801 
4802 // ---------------------------------------------------------------------------
4803 
4804 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4805 {
4806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4807  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4808  Utilities->CallLogPop(480);
4809 }
4810 
4811 // ---------------------------------------------------------------------------
4812 
4814 {
4815  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4816  if(TrackVector.size() == 0)
4817  {
4818  Utilities->CallLogPop(481);
4819  return;
4820  }
4821  for(unsigned int x = 0; x < TrackVector.size(); x++)
4822  {
4823  if(TrackElementAt(1114, x).TrackType == GapJump)
4824  {
4825  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4826  {
4827  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4828  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4829  {
4830  TrackElementAt(1118, x).Conn[0] = -1;
4831  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4832  continue; // to next 'x'
4833  }
4834 // here if gap connection is itself a GapJump
4835  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4836  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4837  // if not clear Conns & CLks
4838  {
4839  TrackElementAt(1121, x).Conn[0] = -1;
4840  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4841  continue; // to next 'x'
4842  }
4843 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4844 // hence no more action needed on these Conns & CLks
4845  }
4846  } // else //gap jump
4847 
4848  } // for x...
4849 // throw Exception("Test Exception");//test
4850  Utilities->CallLogPop(482);
4851 }
4852 
4853 // ---------------------------------------------------------------------------
4854 
4855 void TTrack::ResetSignals(int Caller)
4856 {
4857  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4858  for(unsigned int x = 0; x < TrackVector.size(); x++)
4859  {
4860  if(TrackElementAt(1123, x).TrackType == SignalPost)
4861  {
4862  TrackElementAt(1124, x).Attribute = 0;
4863  TrackElementAt(1514, x).Failed = false;
4864  TrackElementAt(1682, x).CallingOnSet = false; //added at v2.20.3 to clear position light signals
4865  }
4866  }
4867  FailedSignalsVector.clear();
4868  Utilities->CallLogPop(483);
4869 }
4870 
4871 // ---------------------------------------------------------------------------
4872 
4873 void TTrack::ResetPoints(int Caller)
4874 {
4875  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4876  for(unsigned int x = 0; x < TrackVector.size(); x++)
4877  {
4878  if((TrackElementAt(1125, x).TrackType == Points) && (TrackElementAt(1571, x).Failed))
4879  {
4880  TrackElementAt(1126, x).Attribute = 0;
4881  TrackElementAt(1515, x).Failed = false;
4884  TrackElementAt(1569, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4885  TrackElementAt(1570, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 = -1; //added at v2.15.0
4886  }
4887  }
4888  FailedPointsVector.clear();
4889  Utilities->CallLogPop(484);
4890 }
4891 
4892 // ---------------------------------------------------------------------------
4893 
4894 void TTrack::ResetTSRs(int Caller) //added at v2.14.0
4895 {
4896  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetTSRs");
4897  for(unsigned int x = 0; x < TrackVector.size(); x++)
4898  {
4899  if((TrackElementAt(1554, x).TrackType == Simple) && (TrackElementAt(1555, x).Failed))
4900  {
4901  TrackElementAt(1556, x).Failed = false;
4903  TrackElementAt(1573, x).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = -1; //added at v2.15.0
4904  }
4905  }
4906  TSRVector.clear();
4907  Utilities->CallLogPop(2550);
4908 }
4909 
4910 // ---------------------------------------------------------------------------
4911 
4912 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4913 {
4914  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4915  if(TrackVector.empty())
4916  {
4917  TrackMap.clear();
4918  Utilities->CallLogPop(485);
4919  return(true);
4920  }
4921 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4922  THVPair TrackMapKeyPair;
4923 
4924  NewVector.clear();
4925  TTrackMapIterator TrackMapPtr;
4926 
4927  if(!TrackMap.empty())
4928  {
4929  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4930  {
4931  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4932  }
4933  }
4934  if(NewVector.size() != TrackMap.size())
4935  {
4936  throw Exception("Error - Map & Vector different sizes");
4937  }
4938  unsigned int NonZeroCount = 0;
4939 
4940  for(unsigned int x = 0; x < TrackVector.size(); x++)
4941  {
4942  if(TrackElementAt(1127, x).TrackType != Erase)
4943  {
4944  NonZeroCount++;
4945  }
4946  }
4947  if(NewVector.size() != NonZeroCount)
4948  {
4949  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4950  }
4952  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4953  TTrackMapEntry TrackMapEntry;
4954 
4955  for(unsigned int x = 0; x < TrackVector.size(); x++)
4956  {
4957  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4958  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4959  TrackMapEntry.first = TrackMapKeyPair;
4960  TrackMapEntry.second = x;
4961  if(!(TrackMap.insert(TrackMapEntry).second))
4962  {
4963  throw Exception("Error - map insertion failure, TrackVector in error");
4964  }
4965  }
4966 // All track now relocated in TrackVector, reset all Conns & CLks
4967  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4968  {
4969  for(unsigned int y = 0; y < 4; y++)
4970  {
4971  TrackElementAt(1130, x).Conn[y] = -1;
4972  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4973  }
4974  }
4975  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4976  CheckMapAndTrack(4); // test
4977  CheckMapAndInactiveTrack(4); // test
4978  CheckLocationNameMultiMap(8); // test
4979  if(!ResetGapsFromGapMap(1))
4980  {
4981  Utilities->CallLogPop(489);
4982  return(false);
4983  }
4984  Utilities->CallLogPop(490);
4985  return(true);
4986 }
4987 
4988 // ---------------------------------------------------------------------------
4989 
4990 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4991 {
4992  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4993  GapMap.clear();
4994  THVPair GapMapKeyPair, GapMapValuePair;
4995  TGapMapEntry GapMapEntry;
4996 
4997  for(unsigned int x = 0; x < TrackVector.size(); x++)
4998  {
4999  if(TrackElementAt(1132, x).TrackType == GapJump)
5000  {
5001  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
5002  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
5003  GapMapEntry.first = GapMapKeyPair;
5004  if(TrackElementAt(1135, x).Conn[0] == -1)
5005  {
5006  throw Exception("Error - Gap connection == -1 Can't build GapMap");
5007  }
5008  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
5009  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
5010  GapMapEntry.second = GapMapValuePair;
5011  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
5012  {
5013  GapMap.insert(GapMapEntry);
5014  }
5015  }
5016  }
5017  Utilities->CallLogPop(492);
5018 }
5019 
5020 // ---------------------------------------------------------------------------
5021 
5022 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
5023 {
5024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
5025 
5026 //1st pass to check track element locations - split into 2 passes at v2.11.1 so positioning checked before linkages, requested by Dan(#4669) 18/12/21 via Discord
5027  LocError = false;
5028  bool TrackElementPositionsOK = true;
5029 
5030  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5031  {
5032  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
5033  {
5034  continue; // skip blank elements
5035  }
5036 // check footcrossing linkages
5037  if(TrackElementAt(1139, x).TrackType == FootCrossing)
5038  {
5039  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
5040  {
5041  ShowMessage(
5042  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
5043  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
5044  "can't connect to an underpass or vice versa)");
5045  HLoc = TrackElementAt(1141, x).HLoc;
5046  VLoc = TrackElementAt(1142, x).VLoc;
5047  LocError = true;
5048  Utilities->CallLogPop(493);
5049  return(false);
5050  }
5051  }
5052  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5053  {
5054  if(TrackElementAt(1143, x).Link[y] <= 0)
5055  {
5056  continue; // no link
5057  }
5058  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
5059  {
5060  continue; // buffer
5061  }
5062  if(TrackElementAt(1146, x).Config[y] == Gap)
5063  {
5064  continue; // gaps set later from GapMap
5065  }
5066  // get required H & V for track element joining link 'y'
5067  int NewHLoc = TrackElementAt(1437, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
5068  int NewVLoc = TrackElementAt(1438, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
5069  // find track element if present
5070  bool ConnectionFoundFlag;
5071  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
5072  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5073  {
5074  ShowMessage("Can't have a track element adjacent to a continuation exit");
5075  HLoc = TrackElementAt(1152, x).HLoc;
5076  VLoc = TrackElementAt(1153, x).VLoc;
5077  LocError = true;
5078  if(FinalCall)
5079  {
5080  throw Exception("Error in final track linkage - continuation adjacent to another element");
5081  }
5082  Utilities->CallLogPop(1539);
5083  return(false);
5084  }
5085  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
5086  {
5087  continue;
5088  }
5089  if(ConnectionFoundFlag)
5090  {
5091  TrackElementAt(1156, x).Conn[y] = VecPos; //<-- this sets the Conn value
5092  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
5093 
5094  bool ExitSignal = false;
5095  if(y < 2) //changed at v2.15.0 as 64 bit version failed at ...Config[1 - y]... (32 bit less strict and let it go)
5096  {
5097  if(TrackElementAt(1157, x).Config[1 - y] == Signal)
5098  {
5099  ExitSignal = true;
5100  }
5101  }
5102  if(ExitSignal && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
5103  {
5104  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
5105  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
5106  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
5107  TrackElementPositionsOK = false;
5108  }
5109  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
5110  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
5111  {
5112  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
5113  // need room for a train (2 elements) without fouling points or signals
5114  TrackElementPositionsOK = false;
5115  }
5116  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
5117  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
5118  {
5119  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
5120  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
5121  // if continuation next to a signal; also none of these can be a named location, and a continuation can
5122  // be named but needs the adjacent element named too
5123  TrackElementPositionsOK = false;
5124  }
5125  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
5126  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
5127  {
5128  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
5129  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5130  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5131  TrackElementPositionsOK = false;
5132  }
5133 //removed at v2.15.0 as now have a warning for bridge either side of a signal, see below
5134 /* else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage)
5135  {
5136  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5137  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5138  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5139  TrackElementPositionsOK = false;
5140  }*/
5141  else if((TrackElementAt(1564, x).TrackType == SignalPost) && (TrackElementAt(1565, VecPos).TrackType == Bridge) && !Utilities->OverrideAndHideSignalBridgeMessage) //added at v2.15.0
5142  {
5143  ShowMessage("Bridge next to a signal - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
5144  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
5145  // selected - appears as trying to select a signal that is not the next in line from the starting signal
5146  TrackElementPositionsOK = false;
5147  }
5148  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
5149  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5150  {
5151  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
5152  TrackElementPositionsOK = false;
5153  }
5154  // if failed then set the invert values for the offending element
5155  if(!TrackElementPositionsOK)
5156  {
5157  HLoc = TrackElementAt(1183, x).HLoc;
5158  VLoc = TrackElementAt(1184, x).VLoc;
5159  LocError = true;
5160  if(FinalCall)
5161  {
5162  throw Exception("Error in track element positions in FinalCall");
5163  }
5164  Utilities->CallLogPop(494);
5165  return(false);
5166  }
5167  }
5168  // no 'else' here, if there's no link then will be picked up in 2nd pass
5169  }
5170  } // for(unsigned int x=0;x<TrackVector.size();x++)
5171 
5172 
5173 //2nd pass - looking for missing connections
5174  LocError = false;
5175  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5176  {
5177  if(TrackElementAt(1439, x).TrackType == Erase) //Erase isn't used any more as a track type
5178  {
5179  continue; // skip blank elements
5180  }
5181  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5182  {
5183  if(TrackElementAt(1440, x).Link[y] <= 0)
5184  {
5185  continue; // no link
5186  }
5187  if((TrackElementAt(1441, x).TrackType == Buffers) && (TrackElementAt(1442, x).Config[y] == End))
5188  {
5189  continue; // buffer
5190  }
5191  if(TrackElementAt(1443, x).Config[y] == Gap)
5192  {
5193  continue; // gaps set later from GapMap
5194  }
5195  if((TrackElementAt(1444, x).TrackType == Continuation) && (TrackElementAt(1445, x).Config[y] == End))
5196  {
5197  continue; //continuation
5198  }
5199  // get required H & V for track element joining link 'y'
5200  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1448, x).Link[y]][0];
5201  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1449, x).Link[y]][1];
5202  // find track element if present
5203  bool ConnectionFoundFlag;
5204  bool LinkMatchFound = false;
5205  int VecPos = GetVectorPositionFromTrackMap(66, NewHLoc, NewVLoc, ConnectionFoundFlag); //this is the joining element at link 'y'
5206  // if there isn't a connection set the invert values for the offending element
5207  if(ConnectionFoundFlag) //set the ConnLinkPos values
5208  {
5209  for(unsigned int a = 0; a < 4; a++) //links for the joining element at this element's link 'y'
5210  {
5211  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
5212  (TrackElementAt(1181, VecPos).Config[a] != Gap))
5213  {
5214  TrackElementAt(1182, x).ConnLinkPos[y] = a; //for points, 'y == 0' and 'y == 2' will be allocated same value for 'a'
5215  LinkMatchFound = true;
5216  break; //can only match 1 so can break
5217  }
5218  }
5219  if(!LinkMatchFound)
5220  {
5221  HLoc = TrackElementAt(1446, x).HLoc;
5222  VLoc = TrackElementAt(1447, x).VLoc;
5223  LocError = true;
5224  if(FinalCall)
5225  {
5226  throw Exception("Error in final track linkage - - no matching link found");
5227  }
5228  Utilities->CallLogPop(495);
5229  return(false);
5230  }
5231  }
5232  else //error
5233  {
5234  HLoc = TrackElementAt(1185, x).HLoc;
5235  VLoc = TrackElementAt(1186, x).VLoc;
5236  LocError = true;
5237  if(FinalCall)
5238  {
5239  throw Exception("Error in final track linkage - connection not found");
5240  }
5241  Utilities->CallLogPop(2443);
5242  return(false);
5243  }
5244  }
5245  }
5246 //end of 2nd pass
5247 
5248  if(FinalCall)
5249  {
5252  }
5253 
5254 // confirmatiory checks that all ok - or throw error
5255  bool ConnErrorFlag = false;
5256 
5257  for(unsigned int x = 0; x < TrackVector.size(); x++)
5258  {
5259  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
5260  {
5261  ConnErrorFlag = true;
5262  }
5263  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
5264  {
5265  ConnErrorFlag = true;
5266  }
5267  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
5268  {
5269  ConnErrorFlag = true;
5270  }
5271  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
5272  {
5273  ConnErrorFlag = true;
5274  }
5275  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5276  {
5277  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
5278  {
5279  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1) ||
5280  (TrackElementAt(1637, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1638, x).StationEntryStopLinkPos4 != -1))
5281  {
5282  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5283  }
5284  }
5285  }
5286  }
5287  if(ConnErrorFlag)
5288  {
5289  if(FinalCall)
5290  {
5291  throw Exception("ConnError in LinkTrack - Final");
5292  }
5293  else
5294  {
5295  throw Exception("ConnError in LinkTrack - Precheck");
5296  }
5297  }
5298  bool CLkErrorFlag = false;
5299 
5300  for(unsigned int x = 0; x < TrackVector.size(); x++)
5301  {
5302  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
5303  {
5304  CLkErrorFlag = true;
5305  }
5306  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
5307  {
5308  CLkErrorFlag = true;
5309  }
5310  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5311  {
5312  CLkErrorFlag = true;
5313  }
5314  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5315  {
5316  CLkErrorFlag = true;
5317  }
5318  }
5319 
5320  if(CLkErrorFlag)
5321  {
5322  if(FinalCall)
5323  {
5324  throw Exception("CLkError in LinkTrack - Final");
5325  }
5326  else
5327  {
5328  throw Exception("CLkError in LinkTrack - Precheck");
5329  }
5330  }
5331 
5332 // set element lengths to min of 10m
5333  for(unsigned int x = 0; x < TrackVector.size(); x++)
5334  {
5335  if(TrackElementAt(1214, x).TrackType == Erase)
5336  {
5337  continue; // skip blank elements
5338  }
5339  if((TrackElementAt(1215, x).Length01 < 10) && (TrackElementAt(1435, x).Length01 != -1))
5340  {
5341  TrackElementAt(1216, x).Length01 = 10;
5342  }
5343  if((TrackElementAt(1217, x).Length23 < 10) && (TrackElementAt(1218, x).Length23 != -1))
5344  {
5345  TrackElementAt(1219, x).Length23 = 10;
5346  }
5347  }
5348 
5349  if(FinalCall) // ONLY at FinalCall, no point calling twice
5350  {
5351  CalcHLocMinEtc(3);
5352  }
5353 
5354  Utilities->CallLogPop(497);
5355  return(true);
5356 }
5357 
5358 // ---------------------------------------------------------------------------
5359 
5360 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5361 {
5362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5363  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5364  {
5365  if(TrackElementAt(1220, x).TrackType == Erase)
5366  {
5367  continue; // skip blank elements
5368 
5369  }
5370 // check footcrossing linkages
5371  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5372  {
5373  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5374  {
5375  Utilities->CallLogPop(1127);
5376  return(false);
5377  }
5378  }
5379  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5380  {
5381  if(TrackElementAt(1223, x).Link[y] <= 0)
5382  {
5383  continue; // no link
5384  }
5385  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5386  {
5387  continue; // buffer
5388  }
5389  if(TrackElementAt(1226, x).Config[y] == Gap)
5390  {
5391  continue; // gaps set later from GapMap
5392 
5393  }
5394  // get required H & V for track element joining link 'y'
5395  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5396  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5397  // find track element if present
5398  bool ConnectionFoundFlag;
5399  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5400  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5401  {
5402  if(FinalCall)
5403  {
5404  throw Exception("Error in final track linkage - continuation adjacent to another element");
5405  }
5406  Utilities->CallLogPop(1540);
5407  return(false);
5408  }
5409  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5410  {
5411  continue;
5412  }
5413  if(ConnectionFoundFlag)
5414  {
5415  TrackElementAt(1234, x).Conn[y] = VecPos;
5416  bool LinkFoundFlag = false;
5417  // find connecting link in the newly found track element if there is one & make checks
5418  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5419  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5420  {
5421  Utilities->CallLogPop(1541);
5422  return(false);
5423  }
5424  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5425  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5426  {
5427  Utilities->CallLogPop(1542);
5428  return(false);
5429  }
5430  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5431  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5432  {
5433  Utilities->CallLogPop(1543);
5434  return(false);
5435  }
5436  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5437  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5438  {
5439  Utilities->CallLogPop(1981);
5440  return(false);
5441  }
5442 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5443  else if(TrackElementAt(, x).TrackType == Continuation)
5444  {
5445  int H = TrackElementAt(, x).HLoc;
5446  int V = TrackElementAt(, x).VLoc;
5447  bool FoundFlag = false;
5448  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5449  if(FoundFlag)
5450  {
5451  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5452  {
5453  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5454  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5455  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5456  if(FoundFlag)
5457  {
5458  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5459  {
5460  Utilities->CallLogPop();
5461  return false;
5462  }
5463  }
5464  else
5465  {
5466  Utilities->CallLogPop();
5467  return false;
5468  }
5469  }
5470  }
5471  }
5472 */
5473  for(unsigned int a = 0; a < 4; a++)
5474  {
5475  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5476  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5477  {
5478  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5479  // note - this ensures that if the connecting element is a leading point
5480  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5481  // (Points have the same link value for both [0] and [2])
5482  LinkFoundFlag = true;
5483  break; // stop after first find or will find later link for leading point
5484  }
5485  }
5486  if(!LinkFoundFlag)
5487  {
5488  if(FinalCall)
5489  {
5490  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5491  }
5492  Utilities->CallLogPop(1128);
5493  return(false);
5494  }
5495  }
5496  else // if(ConnectionFoundFlag)
5497  {
5498  if(FinalCall)
5499  {
5500  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5501  }
5502  Utilities->CallLogPop(1129);
5503  return(false);
5504  }
5505  }
5506  } // for(unsigned int x=0;x<TrackVector.size();x++)
5507 
5508  if(FinalCall)
5509  {
5512  }
5513 // final check
5514  bool ConnErrorFlag = false;
5515 
5516  for(unsigned int x = 0; x < TrackVector.size(); x++)
5517  {
5518  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5519  {
5520  ConnErrorFlag = true;
5521  }
5522  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5523  {
5524  ConnErrorFlag = true;
5525  }
5526  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5527  {
5528  ConnErrorFlag = true;
5529  }
5530  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5531  {
5532  ConnErrorFlag = true;
5533  }
5534  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5535  {
5536  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5537  {
5538  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1) ||
5539  (TrackElementAt(1639, x).StationEntryStopLinkPos3 != -1) || (TrackElementAt(1640, x).StationEntryStopLinkPos4 != -1))
5540  {
5541  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5542  }
5543  }
5544  }
5545  }
5546  if(ConnErrorFlag)
5547  {
5548  if(FinalCall)
5549  {
5550  throw Exception("ConnError in LinkTrack - Final");
5551  }
5552  else
5553  {
5554  throw Exception("ConnError in LinkTrack - Precheck");
5555  }
5556  }
5557  bool CLkErrorFlag = false;
5558 
5559  for(unsigned int x = 0; x < TrackVector.size(); x++)
5560  {
5561  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5562  {
5563  CLkErrorFlag = true;
5564  }
5565  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5566  {
5567  CLkErrorFlag = true;
5568  }
5569  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5570  {
5571  CLkErrorFlag = true;
5572  }
5573  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5574  {
5575  CLkErrorFlag = true;
5576  }
5577  }
5578 
5579  if(CLkErrorFlag)
5580  {
5581  if(FinalCall)
5582  {
5583  throw Exception("CLkError in LinkTrack - Final");
5584  }
5585  else
5586  {
5587  throw Exception("CLkError in LinkTrack - Precheck");
5588  }
5589  }
5590 // set element lengths to min of 10m
5591  for(unsigned int x = 0; x < TrackVector.size(); x++)
5592  {
5593  if(TrackElementAt(1284, x).TrackType == Erase)
5594  {
5595  continue; // skip blank elements
5596  }
5597  if((TrackElementAt(1285, x).Length01 < 10) && (TrackElementAt(1436, x).Length23 != -1))
5598  {
5599  TrackElementAt(1286, x).Length01 = 10;
5600  }
5601  if((TrackElementAt(1287, x).Length23 < 10) && (TrackElementAt(1288, x).Length23 != -1))
5602  {
5603  TrackElementAt(1289, x).Length23 = 10;
5604  }
5605  }
5606 
5607  if(FinalCall) // ONLY at FinalCall, no point calling twice
5608  {
5609  CalcHLocMinEtc(7);
5610  }
5611  Utilities->CallLogPop(1130);
5612  return(true);
5613 }
5614 
5615 // ---------------------------------------------------------------------------
5616 
5617 bool TTrack::IsTrackLinked(int Caller) // not used any more
5618 {
5619  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5620  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5621  {
5622  if(TrackElementAt(1290, x).TrackType == Erase)
5623  {
5624  Utilities->CallLogPop(498);
5625  return(false);
5626  }
5627 // check foot linkages
5628  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5629  {
5630  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5631  {
5632  Utilities->CallLogPop(499);
5633  return(false);
5634  }
5635  }
5636  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5637  {
5638  if(TrackElementAt(1293, x).Link[y] <= 0)
5639  {
5640  continue; // no link
5641  }
5642  if(TrackElementAt(1294, x).Config[y] == End)
5643  {
5644  continue; // buffer or continuation
5645  }
5646  if(TrackElementAt(1295, x).Config[y] == Gap)
5647  {
5648  continue; // gaps set later from GapMap
5649 
5650  }
5651  // get required H & V for track element joining link 'y'
5652  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5653  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5654  // find track element if present
5655  bool ConnectionFoundFlag = false;
5656  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5657  if(ConnectionFoundFlag)
5658  {
5659  TrackElementAt(1300, x).Conn[y] = VecPos;
5660  // find connecting link in the newly found track element if there is one & make buffer check
5661  bool LinkFoundFlag = false;
5662  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5663  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5664  {
5665  Utilities->CallLogPop(500);
5666  return(false);
5667  }
5668  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5669  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5670  {
5671  Utilities->CallLogPop(501);
5672  return(false);
5673  }
5674  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5675  {
5676  Utilities->CallLogPop(502);
5677  return(false);
5678  }
5679  else
5680  {
5681  for(unsigned int a = 0; a < 4; a++)
5682  {
5683  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5684  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5685  {
5686  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5687  // note - this ensures that if the connecting element is a leading point
5688  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5689  // (Points have the same link value for both [0] and [2])
5690  LinkFoundFlag = true;
5691  break; // stop after first find or will find later link for leading point
5692  }
5693  }
5694  }
5695  if(!LinkFoundFlag)
5696  {
5697  Utilities->CallLogPop(503);
5698  return(false);
5699  }
5700  }
5701  else // if(ConnectionFoundFlag)
5702  {
5703  Utilities->CallLogPop(504);
5704  return(false);
5705  }
5706  }
5707  } // for(unsigned int x=0;x<TrackVector.size();x++)
5708 
5709 // final check
5710  bool ConnErrorFlag = false;
5711 
5712  for(unsigned int x = 0; x < TrackVector.size(); x++)
5713  {
5714  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5715  {
5716  ConnErrorFlag = true;
5717  }
5718  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5719  {
5720  ConnErrorFlag = true;
5721  }
5722  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5723  {
5724  ConnErrorFlag = true;
5725  }
5726  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5727  {
5728  ConnErrorFlag = true;
5729  }
5730  }
5731  if(ConnErrorFlag)
5732  {
5733  Utilities->CallLogPop(505);
5734  return(false);
5735  }
5736  bool CLkErrorFlag = false;
5737 
5738  for(unsigned int x = 0; x < TrackVector.size(); x++)
5739  {
5740  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5741  {
5742  CLkErrorFlag = true;
5743  }
5744  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5745  {
5746  CLkErrorFlag = true;
5747  }
5748  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5749  {
5750  CLkErrorFlag = true;
5751  }
5752  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5753  {
5754  CLkErrorFlag = true;
5755  }
5756  }
5757 
5758  if(CLkErrorFlag)
5759  {
5760  Utilities->CallLogPop(506);
5761  return(false);
5762  }
5763  Utilities->CallLogPop(507);
5764  return(true);
5765 }
5766 
5767 // ---------------------------------------------------------------------------
5768 
5770 {
5771  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5772  int Position1, Position2;
5773  TTrackElement TrackElement1, TrackElement2;
5774  TGapMapIterator GapMapPtr;
5775 
5776  if(!GapMap.empty())
5777  {
5778  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5779  {
5780  int HLoc1 = GapMapPtr->first.first;
5781  int VLoc1 = GapMapPtr->first.second;
5782  int HLoc2 = GapMapPtr->second.first;
5783  int VLoc2 = GapMapPtr->second.second;
5784  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5785  {
5786  throw Exception("Failed to find H & V for gap1, GapMap in error");
5787  }
5788  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5789  {
5790  throw Exception("Failed to find H & V for gap2, GapMap in error");
5791  }
5792  if(TrackElementAt(9, Position1).TrackType != GapJump)
5793  {
5794  throw Exception("Element at Pos1 not a gap, GapMap in error");
5795  }
5796  if(TrackElementAt(10, Position2).TrackType != GapJump)
5797  {
5798  throw Exception("Element at Pos2 not a gap, GapMap in error");
5799  }
5800  TrackElementAt(11, Position1).Conn[0] = Position2;
5801  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5802  TrackElementAt(13, Position2).Conn[0] = Position1;
5803  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5804  }
5805  }
5806  Utilities->CallLogPop(510);
5807  return(true);
5808 }
5809 
5810 // ---------------------------------------------------------------------------
5811 
5812 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5813 {
5814 // TIMPair MapEntry;
5815  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5816  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5817  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5818  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5819  TLocationNameMultiMapEntry LocationNameEntry;
5820 
5821  LocationNameEntry.first = TrackElement.LocationName;
5822  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5823  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5824  {
5825 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5826 // could arise when loading old railways with multiple NonStationNamedLocs
5827  bool FoundFlag = false;
5828  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5829  if(FoundFlag)
5830  {
5831  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5832  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5833  {
5834  Utilities->CallLogPop(1813);
5835  return;
5836  }
5837  }
5838  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5839  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5840  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5841  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5842  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5843  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5844  if(TrackElement.FixedNamedLocationElement)
5845  {
5846  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5847  LocationNameMultiMap.insert(LocationNameEntry);
5848  }
5849  if(TrackElement.HLoc < HLocMin)
5850  {
5851  HLocMin = TrackElement.HLoc;
5852  }
5853  if(TrackElement.HLoc > HLocMax)
5854  {
5855  HLocMax = TrackElement.HLoc;
5856  }
5857  if(TrackElement.VLoc < VLocMin)
5858  {
5859  VLocMin = TrackElement.VLoc;
5860  }
5861  if(TrackElement.VLoc > VLocMax)
5862  {
5863  VLocMax = TrackElement.VLoc;
5864  }
5865  }
5866  else
5867  {
5868 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5869 // shouldn't arise but leave in as a safeguard
5870  bool FoundFlag = false;
5871  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5872  if(FoundFlag)
5873  {
5874  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5875  {
5876  Utilities->CallLogPop(1814);
5877  return;
5878  }
5879  }
5880  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5881  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5882  {
5883  TrackMapKeyPair.first = TrackElement.HLoc;
5884  TrackMapKeyPair.second = TrackElement.VLoc;
5885  TrackMapEntry.first = TrackMapKeyPair;
5886  TrackMapEntry.second = TrackVector.size() - 1;
5887  TrackMap.insert(TrackMapEntry);
5888  if(TrackElement.FixedNamedLocationElement)
5889  {
5890  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5891  LocationNameMultiMap.insert(LocationNameEntry);
5892  }
5893  if(TrackElement.HLoc < HLocMin)
5894  {
5895  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5896  }
5897  if(TrackElement.HLoc > HLocMax)
5898  {
5899  HLocMax = TrackElement.HLoc;
5900  }
5901  if(TrackElement.VLoc < VLocMin)
5902  {
5903  VLocMin = TrackElement.VLoc;
5904  }
5905  if(TrackElement.VLoc > VLocMax)
5906  {
5907  VLocMax = TrackElement.VLoc;
5908  }
5909  }
5910  }
5911 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5912 // CheckMapAndInactiveTrack(6);//test
5913 
5914 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5915 // with the Platforms until layout fully loaded
5916  Utilities->CallLogPop(511);
5917 }
5918 
5919 // ---------------------------------------------------------------------------
5920 
5921 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5922 {
5923  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5924  AnsiString(VLoc));
5925  THVPair TrackMapKeyPair;
5926 
5927  FoundFlag = false;
5928  TTrackMapIterator TrackMapPtr;
5929 
5930  TrackMapKeyPair.first = HLoc;
5931  TrackMapKeyPair.second = VLoc;
5932  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5933  if(TrackMapPtr == TrackMap.end())
5934  {
5935  Utilities->CallLogPop(512);
5936  return(-1); // nothing found
5937  }
5938  else
5939  {
5940  FoundFlag = true;
5941  Utilities->CallLogPop(513);
5942  return(TrackMapPtr->second);
5943  }
5944 }
5945 
5946 // ---------------------------------------------------------------------------
5947 
5948 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5949 {
5950  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5951  AnsiString(VLoc));
5952  THVPair TrackMapKeyPair;
5953  TTrackMapIterator TrackMapPtr;
5954 
5955  TrackMapKeyPair.first = HLoc;
5956  TrackMapKeyPair.second = VLoc;
5957  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5958  if(TrackMapPtr == TrackMap.end())
5959  {
5960  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5961  throw Exception(Message);
5962  }
5963  else
5964  {
5965  Utilities->CallLogPop(1943);
5966  return(TrackElementAt(871, TrackMapPtr->second));
5967  }
5968 }
5969 
5970 // ---------------------------------------------------------------------------
5971 
5972 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5973 { //modded at v2.9.2 to make Map & Vector references
5974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5975  AnsiString(VLoc));
5976  THVPair MapKeyPair;
5977  TTrackMapIterator MapPtr;
5978 
5979  MapKeyPair.first = HLoc;
5980  MapKeyPair.second = VLoc;
5981  MapPtr = Map.find(MapKeyPair);
5982  if(MapPtr == Map.end())
5983  {
5984  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5985  throw Exception(Message);
5986  }
5987  else
5988  {
5989  Utilities->CallLogPop(2280);
5990  return(Vector.at(MapPtr->second));
5991  }
5992 }
5993 
5994 // ---------------------------------------------------------------------------
5995 
5997 {
5998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5999  AnsiString(VLoc));
6000  THVPair InactiveTrackMapKeyPair;
6001  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
6002 
6003  InactiveTrackMapKeyPair.first = HLoc;
6004  InactiveTrackMapKeyPair.second = VLoc;
6005  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
6006  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
6007  {
6008  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
6009  throw Exception(Message);
6010  }
6011  else
6012  {
6013  Utilities->CallLogPop(1949);
6014  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
6015  }
6016 }
6017 
6018 // ---------------------------------------------------------------------------
6019 
6020 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
6021 {
6022  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6023  bool Present = true;
6024  THVPair TrackMapKeyPair;
6025  TTrackMapIterator TrackMapPtr;
6026 
6027  TrackMapKeyPair.first = HLoc;
6028  TrackMapKeyPair.second = VLoc;
6029  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
6030  if(TrackMapPtr == TrackMap.end())
6031  {
6032  Present = false;
6033  }
6034  Utilities->CallLogPop(2057);
6035  return(Present);
6036 }
6037 
6038 // ---------------------------------------------------------------------------
6039 
6040 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
6041 {
6042  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
6043  AnsiString(VLoc));
6044  bool Present = true;
6045  THVPair InactiveTrackMapKeyPair;
6046  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
6047 
6048  InactiveTrackMapKeyPair.first = HLoc;
6049  InactiveTrackMapKeyPair.second = VLoc;
6050  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
6051  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
6052  {
6053  Present = false;
6054  }
6055  Utilities->CallLogPop(2058);
6056  return(Present);
6057 }
6058 
6059 // ---------------------------------------------------------------------------
6060 
6061 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
6062 // max number of elements is 2, for platforms
6063 // note that both elements of RetPair may be the same, if only one present in map
6064 {
6065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
6066  AnsiString(VLoc));
6067  THVPair InactiveTrackMapKeyPair;
6068  TIMPair RetPair;
6069  TInactiveTrackRange InactiveTrackRange;
6070 
6071  FoundFlag = false;
6072  InactiveTrackMapKeyPair.first = HLoc;
6073  InactiveTrackMapKeyPair.second = VLoc;
6074  if(InactiveTrack2MultiMap.empty())
6075  {
6076  RetPair.first = 0;
6077  RetPair.second = 0;
6078  Utilities->CallLogPop(1815);
6079  return(RetPair); // map empty
6080  }
6081  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
6082  if(InactiveTrackRange.first == InactiveTrackRange.second)
6083  {
6084  RetPair.first = 0;
6085  RetPair.second = 0;
6086  Utilities->CallLogPop(514);
6087  return(RetPair); // nothing found
6088  }
6089  else
6090  {
6091  RetPair.first = InactiveTrackRange.first->second;
6092  RetPair.second = (--InactiveTrackRange.second)->second;
6093  FoundFlag = true;
6094  Utilities->CallLogPop(515);
6095  return(RetPair);
6096  }
6097 }
6098 
6099 // ---------------------------------------------------------------------------
6100 
6101 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition) //changed at v2.13.0 to return true for failed but matching points
6102 {
6103 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
6104  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
6105  AnsiString(DivergingPosition));
6106  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
6107  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
6108  int SpeedTag1 = T1.SpeedTag;
6109  int SpeedTag2 = T2.SpeedTag;
6110 
6111  if((T1.Attribute) != (T2.Attribute))
6112  {
6113  Utilities->CallLogPop(516);
6114  return(false);
6115  }
6116  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
6117  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
6118  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
6119  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
6120  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
6121  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
6122  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
6123  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
6124  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
6125  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
6126  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
6127  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
6128  {
6129  Utilities->CallLogPop(517);
6130  return(true);
6131  }
6132  else
6133  {
6134  Utilities->CallLogPop(518);
6135  return(false);
6136  }
6137 }
6138 
6139 // ---------------------------------------------------------------------------
6140 
6141 /*
6142  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
6143  {
6144  if(lower.second < higher.second) return true;
6145  else if(lower.second > higher.second) return false;
6146  else if(lower.second == higher.second)
6147  {
6148  if(lower.first < higher.first) return true;
6149  }
6150  return false;
6151  }
6152 */
6153 // ---------------------------------------------------------------------------
6154 
6155 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6156 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
6157 {
6158  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
6159  if(TrackElement.TrackType != GapJump)
6160  {
6161  throw Exception("Error, Wrong track type in PlotGap");
6162  }
6163  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
6164  {
6165  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
6166  }
6167  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
6168  {
6169  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
6170  }
6171  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
6172  {
6173  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
6174  }
6175  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
6176  {
6177  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
6178  }
6179  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
6180  {
6181  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
6182  }
6183  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
6184  {
6185  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
6186  }
6187  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
6188  {
6189  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
6190  }
6191  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
6192  {
6193  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
6194  }
6195  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
6196  {
6197  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
6198  }
6199  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
6200  {
6201  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
6202  }
6203  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
6204  {
6205  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
6206  }
6207  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
6208  {
6209  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
6210  }
6211  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
6212  {
6213  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
6214  }
6215  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
6216  {
6217  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
6218  }
6219  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
6220  {
6221  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
6222  }
6223  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
6224  {
6225  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
6226  }
6227  Utilities->CallLogPop(1101);
6228 }
6229 
6230 // ---------------------------------------------------------------------------
6231 
6232 void TTrack::PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp) //added for multiplayer to add overlays where coupled
6233 {
6234  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotContinuation," + TrackElement.LogTrack(1));
6235  TrackElement.PlotVariableTrackElement(7, Disp);
6236  if(!MultiplayerOverlayMap.empty()) //if it is empty then no overlays needed [map of key = THVPair, value = graphic pointer]
6237  {
6238  THVPair PosPair;
6239  PosPair.first = TrackElement.HLoc;
6240  PosPair.second = TrackElement.VLoc;
6241  TMultiplayerOverlayMap::iterator MOMIt = MultiplayerOverlayMap.find(PosPair);
6242  if(MOMIt != MultiplayerOverlayMap.end()) //if it is then no overlay is needed
6243  {
6244  Disp->PlotOutput(283, TrackElement.HLoc * 16, TrackElement.VLoc * 16, MOMIt->second);
6245  }
6246  }
6247  Utilities->CallLogPop(2403);
6248 }
6249 
6250 // ---------------------------------------------------------------------------
6251 
6252 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
6253 {
6254  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
6255  if(TrackElement.TrackType != Points)
6256  {
6257  throw Exception("Error, Wrong track type in PlotPoints");
6258  }
6259  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
6260  //check if a blue location and if so plot the blue element again - named or not as appropriate - added at v2.18.0 for blue locs at points
6261  bool FoundFlag = false;
6262  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(32, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6263  if(IMPair.first > 0) //can only have one entry in IMPair for points
6264  {
6265  TTrackElement ITE = InactiveTrackElementAt(1409, IMPair.first);
6266  if(ITE.SpeedTag == 131)
6267  {
6268  ITE.PlotVariableTrackElement(8, Disp); //plot the blue square again
6269  }
6270  }
6271  TrackElement.PlotVariableTrackElement(4, Disp);
6272  if(BothFillets)
6273  {
6274  if(TrackElement.SpeedTag < 28)
6275  {
6276  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
6277  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
6278  }
6279  else if(TrackElement.SpeedTag < 132)
6280  {
6281  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
6282  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
6283  }
6284  else
6285  {
6286  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
6287  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
6288  }
6289  }
6290  else if(!TrackElement.Failed) //not failed
6291  {
6292  if(TrackElement.SpeedTag < 28)
6293  {
6294  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6295  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6296  }
6297  else if(TrackElement.SpeedTag < 132)
6298  {
6299  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6300  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6301  }
6302  else
6303  {
6304  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6305  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6306  }
6307  }
6308  else //failed in fixed position
6309  {
6310  if(TrackElement.SpeedTag < 28)
6311  {
6312  Disp->PlotOutput(284, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6313  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]); //0 to 7 incl after subtraction
6314  }
6315  else if(TrackElement.SpeedTag < 132)
6316  {
6317  Disp->PlotOutput(285, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6318  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]); //8 to 23 incl after subtraction
6319  }
6320  else
6321  {
6322  Disp->PlotOutput(286, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
6323  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]); //24 to 31 incl after subtraction
6324  }
6325  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6326  }
6327 // replot platform if required
6328  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6329  bool BlueLoc = false;
6330  if(FoundFlag)
6331  {
6332  TTrackElement TE = GetInactiveTrackElementFromTrackMap(6, TrackElement.HLoc, TrackElement.VLoc);
6333  if(TE.SpeedTag == 131) //non-station named location - don't want to replot these or the track is obscured - added at v2.18.0
6334  {
6335  BlueLoc = true;
6336  }
6337  }
6338  if(FoundFlag && !BlueLoc)
6339  {
6340  // only one platform possible at points so only need to plot IMPair.first
6341  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
6342  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
6343  }
6344  Utilities->CallLogPop(519);
6345 }
6346 
6347 // ---------------------------------------------------------------------------
6348 
6349 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
6350 {
6351 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
6352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
6353  bool FoundFlag = false;
6354  if(TrackElement.TrackType != SignalPost)
6355  {
6356  throw Exception("Error, Wrong track type in PlotSignal");
6357  }
6358  if(!TrackElement.Failed) //added at v2.13.0
6359  {
6360  for(int x = 0; x < 40; x++)
6361  {
6362  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
6363  {
6364  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6365  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6366  // in case existing signal is a double yellow
6367  // plot platforms if present
6368  // Graphics::TBitmap* SignalPlatformGraphic;
6369  // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
6370  // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6371  // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6372  // to not be plotted with the above function.
6373 
6374  //replot the blue square to cover the blank area - added at v2.18.0
6375  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(36, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
6376  if(FoundFlag) //changed at v2.23.2, was if(IMPair.first > 0) but this excluded vector position 0 which it would be if it was the first inactive element
6377  {
6378  TTrackElement ITE = InactiveTrackElementAt(1414, IMPair.first); //can only have one entry in IMPair for a blue square (second entry is only for second platform)
6379  if(ITE.SpeedTag == 131)
6380  {
6381  ITE.PlotVariableTrackElement(9, Disp); //plot the blue square again to cover the blank area
6382  }
6383  }
6384 
6385  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6386  // now plot signal (double yellow overwrites most of signal platform if present)
6387  // additions at version 0.6 for other aspects & ground sigs
6388  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6389  {
6390  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6391  }
6392  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6393  {
6394  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6395  }
6396  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6397  {
6398  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6399  }
6400  else // 4 aspect
6401  {
6402  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6403  }
6404  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6405  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6406  {
6407  if(TrackElement.SpeedTag == 68)
6408  {
6409  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6410  }
6411  if(TrackElement.SpeedTag == 69)
6412  {
6413  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6414  }
6415  if(TrackElement.SpeedTag == 70)
6416  {
6417  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6418  }
6419  if(TrackElement.SpeedTag == 71)
6420  {
6421  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6422  }
6423  if(TrackElement.SpeedTag == 72)
6424  {
6425  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6426  }
6427  if(TrackElement.SpeedTag == 73)
6428  {
6429  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6430  }
6431  if(TrackElement.SpeedTag == 74)
6432  {
6433  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6434  }
6435  if(TrackElement.SpeedTag == 75)
6436  {
6437  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6438  }
6439  }
6440  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6441  // ground signal calling on, need to use normal proceed aspect
6442  {
6443  for(int x = 0; x < 40; x++)
6444  {
6445  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6446  {
6447  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6448  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6449  // plot special signal platform if present
6450  Graphics::TBitmap* SignalPlatformGraphic;
6451  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(37, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6452  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6453  {
6454  TTrackElement ITE = InactiveTrackElementAt(1415, IMPair.first);
6455  if(ITE.SpeedTag == 131)
6456  {
6457  ITE.PlotVariableTrackElement(10, Disp); //plot the blue square again to cover the blank area
6458  }
6459  }
6460  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6461  // now plot signal
6462  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6463  }
6464  }
6465  }
6466  break;
6467  }
6468  }
6469  }
6470  else //failed added at v2.13.0
6471  {
6472  if(TrackElement.SigAspect != TTrackElement::GroundSignal)
6473  {
6474  for(int x = 0; x < 8; x++)
6475  {
6476  if(FailedSigTable[x].SpeedTag == TrackElement.SpeedTag)
6477  {
6478  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6479  Disp->PlotSignalBlank(2, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6480  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(38, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6481  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6482  {
6483  TTrackElement ITE = InactiveTrackElementAt(1416, IMPair.first);
6484  if(ITE.SpeedTag == 131)
6485  {
6486  ITE.PlotVariableTrackElement(11, Disp); //plot the blue square again to cover the blank area
6487  }
6488  }
6489  PlotSignalPlatforms(2, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6490  Disp->PlotOutput(287, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedSigTable[x].SigPtr);
6491  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6492  break;
6493  }
6494  }
6495  }
6496  else
6497  {
6498  for(int x = 0; x < 8; x++)
6499  {
6500  if(FailedGroundSigTable[x].SpeedTag == TrackElement.SpeedTag)
6501  {
6502  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6503  Disp->PlotSignalBlank(3, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6504  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(39, TrackElement.HLoc, TrackElement.VLoc, FoundFlag); //added at v2.18.0
6505  if(IMPair.first > 0) //can only have one entry in IMPair for signals
6506  {
6507  TTrackElement ITE = InactiveTrackElementAt(1417, IMPair.first);
6508  if(ITE.SpeedTag == 131)
6509  {
6510  ITE.PlotVariableTrackElement(12, Disp); //plot the blue square again to cover the blank area
6511  }
6512  }
6513  PlotSignalPlatforms(3, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6514  Disp->PlotOutput(288, TrackElement.HLoc * 16, TrackElement.VLoc * 16, FailedGroundSigTable[x].SigPtr);
6515  Disp->GetImage()->Canvas->Draw((TrackElement.HLoc - Display->DisplayOffsetH) * 16, (TrackElement.VLoc - Display->DisplayOffsetV) * 16, RailGraphics->BlackOctagon); //indicates that it has failed
6516  break;
6517  }
6518  }
6519  }
6520  }
6521  Utilities->CallLogPop(520);
6522 }
6523 
6524 // ---------------------------------------------------------------------------
6525 
6526 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6527 {
6528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6529  bool FoundFlag;
6530  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6531 
6532  if(!FoundFlag)
6533  {
6534  Utilities->CallLogPop(2112);
6535  return;
6536  }
6537  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6538  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6539 
6540  // don't want 'else if' for the below as may need to plot 2 platforms
6541  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6542  {
6543  if(IAElement1.LocationName == "") // '2' will be same
6544  {
6545  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6546  }
6547  else
6548  {
6549  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6550  }
6551  }
6552  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6553  {
6554  if(IAElement1.LocationName == "") // '2' will be same
6555  {
6556  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6557  }
6558  else
6559  {
6560  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6561  }
6562  }
6563  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6564  {
6565  if(IAElement1.LocationName == "") // '2' will be same
6566  {
6567  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6568  }
6569  else
6570  {
6571  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6572  }
6573  }
6574  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6575  {
6576  if(IAElement1.LocationName == "") // '2' will be same
6577  {
6578  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6579  }
6580  else
6581  {
6582  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6583  }
6584  }
6585  Utilities->CallLogPop(2113);
6586 }
6587 
6588 // ---------------------------------------------------------------------------
6589 
6590 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6591 {
6592 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6594  AnsiString(VLoc));
6595 // find topmost LC, opening them all (to trains) in turn
6596  int UpStep = 0;
6597 
6598  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6599  {
6600  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6601  UpStep--;
6602  }
6603 // now find bottommost LC, opening them all (to trains) in turn
6604  int DownStep = 1;
6605 
6606  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6607  {
6608  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6609  DownStep++;
6610  }
6611 // find leftmost LC, opening them all (to trains) in turn
6612  int LeftStep = 0;
6613 
6614  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6615  {
6616  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6617  LeftStep--;
6618  }
6619 // now find rightmost LC, opening them all (to trains) in turn
6620  int RightStep = 1;
6621 
6622  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6623  {
6624  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6625  RightStep++;
6626  }
6627  Utilities->CallLogPop(1915);
6628 }
6629 
6630 // ---------------------------------------------------------------------------
6631 
6632 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6633 {
6634  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6635 // work upwards setting all to manual
6636  int UpStep = -1;
6637 
6638  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6639  {
6640  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6641  UpStep--;
6642  }
6643 // work downwards setting all to manual
6644  int DownStep = 1;
6645 
6646  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6647  {
6648  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6649  DownStep++;
6650  }
6651 // work leftwards setting all to manual
6652  int LeftStep = -1;
6653 
6654  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6655  {
6656  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6657  LeftStep--;
6658  }
6659 // work rightwards setting all to manual
6660  int RightStep = 1;
6661 
6662  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6663  {
6664  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6665  RightStep++;
6666  }
6667  Utilities->CallLogPop(2242);
6668 }
6669 
6670 // ---------------------------------------------------------------------------
6671 
6672 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6673 {
6674  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6675  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6676  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6677  {
6678  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6679  {
6680  BarriersDownVector.at(x).TypeOfRoute = 2;
6681  break;
6682  }
6683  }
6684  Utilities->CallLogPop(2243);
6685 }
6686 
6687 // ---------------------------------------------------------------------------
6688 
6689 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6690 {
6691  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6692 // work upwards
6693  int UpStep = 0; //start with this location
6694 
6695  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6696  {
6697  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6698  {
6699  Utilities->CallLogPop(2244);
6700  return(true);
6701  }
6702  UpStep--;
6703  }
6704 // work downwards
6705  int DownStep = 1;
6706 
6707  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6708  {
6709  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6710  {
6711  Utilities->CallLogPop(2245);
6712  return(true);
6713  }
6714  DownStep++;
6715  }
6716 // work leftwards
6717  int LeftStep = -1;
6718 
6719  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6720  {
6721  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6722  {
6723  Utilities->CallLogPop(2246);
6724  return(true);
6725  }
6726  LeftStep--;
6727  }
6728 // work rightwards
6729  int RightStep = 1;
6730 
6731  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6732  {
6733  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6734  {
6735  Utilities->CallLogPop(2247);
6736  return(true);
6737  }
6738  RightStep++;
6739  }
6740  Utilities->CallLogPop(2248);
6741  return(false);
6742 }
6743 
6744 // ---------------------------------------------------------------------------
6745 
6746 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6747 {
6748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6749  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6750  {
6751  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6752  {
6753  BDVectorPos = x;
6754  Utilities->CallLogPop(2249);
6755  return(true);
6756  }
6757  }
6758  BDVectorPos = -1;
6759  Utilities->CallLogPop(2250);
6760  return(false);
6761 }
6762 
6763 // ---------------------------------------------------------------------------
6764 
6765 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6766 // open to trains
6767 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6768 {
6769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6770  AnsiString(VLoc));
6771  if(!IsLCAtHV(4, HLoc, VLoc))
6772  {
6773  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6774  }
6775  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6776  {
6777  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6778  }
6779 // check for adjacent LCs & if so open (to trains)
6780  if(BaseElementSpeedTag == 1) // hor track element
6781  {
6782  // find topmost LC, opening them all (to trains) in turn
6783  int UpStep = 0;
6784  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6785  {
6786  UpStep--;
6787  }
6788  UpStep++;
6789  // now find bottommost LC, opening them all (to trains) in turn
6790  int DownStep = 1;
6791  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6792  {
6793  DownStep++;
6794  }
6795  DownStep--;
6796  // now plot graphics, UpStep is smallest & DownStep largest
6797  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6798  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6799  Graphics::TBitmap *RouteGraphic;
6800  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6801  if(TypeOfRoute == 1)
6802  {
6803  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6804  }
6805  else if(TypeOfRoute == 0)
6806  {
6807  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6808  }
6809  else //manual - no route
6810  {
6811  RouteGraphic = BaseGraphic;
6812  }
6813 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6814 // LinkSigRouteGraphicsPtr[1] ver }
6815 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6816 // LinkNonSigRouteGraphicsPtr[1] ver }
6817 
6818  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6819  {
6820  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6821  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6822  if(!Manual)
6823  {
6824  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6825  }
6826  else
6827  {
6828  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6829  }
6830  }
6831  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6832  {
6833  if(UpStep == 0)
6834  {
6835  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6836  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6837  if(!Manual)
6838  {
6839  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6840  }
6841  else
6842  {
6843  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6844  }
6845  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6846  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6847  if(!Manual)
6848  {
6849  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6850  }
6851  else
6852  {
6853  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6854  }
6855  }
6856  else
6857  {
6858  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6859  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6860  if(!Manual)
6861  {
6862  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6863  }
6864  else
6865  {
6866  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6867  }
6868  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6869  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6870  if(!Manual)
6871  {
6872  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6873  }
6874  else
6875  {
6876  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6877  }
6878  }
6879  }
6880  else // at least one plain graphic
6881  {
6882  if(UpStep == 0)
6883  {
6884  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6885  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6886  if(!Manual)
6887  {
6888  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6889  }
6890  else
6891  {
6892  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6893  }
6894  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6895  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6896  if(!Manual)
6897  {
6898  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6899  }
6900  else
6901  {
6902  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6903  }
6904  }
6905  else if(DownStep == 0)
6906  {
6907  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6908  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6909  if(!Manual)
6910  {
6911  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6912  }
6913  else
6914  {
6915  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6916  }
6917  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6918  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6919  if(!Manual)
6920  {
6921  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6922  }
6923  else
6924  {
6925  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6926  }
6927  }
6928  else
6929  {
6930  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6931  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6932  if(!Manual)
6933  {
6934  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6935  }
6936  else
6937  {
6938  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6939  }
6940  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6941  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6942  if(!Manual)
6943  {
6944  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6945  }
6946  else
6947  {
6948  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6949  }
6950  }
6951  for(int x = (UpStep + 1); x < DownStep; x++)
6952  {
6953  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6954  if(x == 0)
6955  {
6956  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6957  }
6958  else
6959  {
6960  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6961  }
6962  if(!Manual)
6963  {
6964  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6965  }
6966  else
6967  {
6968  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6969  }
6970  }
6971  }
6972  Disp->Update();
6973  Utilities->CallLogPop(1958);
6974  return;
6975  }
6976 
6977  else // ver track element
6978  {
6979  // find leftmost LC, opening them all (to trains) in turn
6980  int LStep = 0;
6981  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6982  {
6983  LStep--;
6984  }
6985  LStep++;
6986  // now find rightmost LC, opening them all (to trains) in turn
6987  int RStep = 1;
6988  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6989  {
6990  RStep++;
6991  }
6992  RStep--;
6993  // now plot graphics, LStep is smallest & RStep largest
6994  Graphics::TBitmap *RouteGraphic;
6995  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6996  if(TypeOfRoute == 1)
6997  {
6998  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6999  }
7000  else if(TypeOfRoute == 0)
7001  {
7002  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7003  }
7004  else //manual
7005  {
7006  RouteGraphic = BaseGraphic;
7007  }
7008 // LinkSigRouteGraphicsPtr[0] hor } pref dir
7009 // LinkSigRouteGraphicsPtr[1] ver }
7010 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
7011 // LinkNonSigRouteGraphicsPtr[1] ver }
7012  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7013  {
7014  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7015  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
7016  if(!Manual)
7017  {
7018  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7019  }
7020  else
7021  {
7022  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7023  }
7024  }
7025  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7026  {
7027  if(LStep == 0)
7028  {
7029  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7030  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
7031  if(!Manual)
7032  {
7033  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7034  }
7035  else
7036  {
7037  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7038  }
7039  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7040  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7041  if(!Manual)
7042  {
7043  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7044  }
7045  else
7046  {
7047  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7048  }
7049  }
7050  else
7051  {
7052  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7053  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7054  if(!Manual)
7055  {
7056  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7057  }
7058  else
7059  {
7060  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7061  }
7062  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7063  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7064  if(!Manual)
7065  {
7066  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7067  }
7068  else
7069  {
7070  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7071  }
7072  }
7073  }
7074  else // at least one plain graphic
7075  {
7076  if(LStep == 0)
7077  {
7078  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7079  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
7080  if(!Manual)
7081  {
7082  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7083  }
7084  else
7085  {
7086  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7087  }
7088  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7089  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7090  if(!Manual)
7091  {
7092  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7093  }
7094  else
7095  {
7096  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7097  }
7098  }
7099  else if(RStep == 0)
7100  {
7101  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7102  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7103  if(!Manual)
7104  {
7105  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7106  }
7107  else
7108  {
7109  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7110  }
7111  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7112  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
7113  if(!Manual)
7114  {
7115  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7116  }
7117  else
7118  {
7119  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7120  }
7121  }
7122  else
7123  {
7124  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7125  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
7126  if(!Manual)
7127  {
7128  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7129  }
7130  else
7131  {
7132  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7133  }
7134  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7135  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
7136  if(!Manual)
7137  {
7138  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7139  }
7140  else
7141  {
7142  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7143  }
7144  }
7145  for(int x = (LStep + 1); x < RStep; x++)
7146  {
7147  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7148  if(x == 0)
7149  {
7150  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
7151  }
7152  else
7153  {
7154  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
7155  }
7156  if(!Manual)
7157  {
7158  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7159  }
7160  else
7161  {
7162  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7163  }
7164  }
7165  }
7166  Disp->Update();
7167  Utilities->CallLogPop(1896);
7168  return;
7169  }
7170 }
7171 
7172 // ---------------------------------------------------------------------------
7173 
7174 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
7175 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7176 {
7177  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
7178  AnsiString(HLoc) + "," + AnsiString(VLoc));
7179  if(!IsLCAtHV(29, HLoc, VLoc))
7180  {
7181  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7182  }
7183  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7184  {
7185  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
7186  }
7187 // check for adjacent LCs & if so open (to trains)
7188  if(BaseElementSpeedTag == 1) // hor track element
7189  {
7190  // find topmost LC, opening them all (to trains) in turn
7191  int UpStep = 0;
7192  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7193  {
7194  UpStep--;
7195  }
7196  UpStep++;
7197  // now find bottommost LC, opening them all (to trains) in turn
7198  int DownStep = 1;
7199  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
7200  {
7201  DownStep++;
7202  }
7203  DownStep--;
7204  // now plot graphics, UpStep is smallest & DownStep largest
7205  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7206  {
7207  if(!Manual)
7208  {
7209  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
7210  }
7211  else
7212  {
7213  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
7214  }
7215  }
7216  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
7217  {
7218  if(!Manual)
7219  {
7220  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7221  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7222  }
7223  else
7224  {
7225  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7226  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7227  }
7228  }
7229  else // at least one plain graphic
7230  {
7231  if(!Manual)
7232  {
7233  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
7234  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
7235  for(int x = (UpStep + 1); x < DownStep; x++)
7236  {
7237  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
7238  }
7239  }
7240  else
7241  {
7242  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
7243  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
7244  for(int x = (UpStep + 1); x < DownStep; x++)
7245  {
7246  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
7247  }
7248  }
7249  }
7250  // set markers
7251  for(int x = UpStep; x <= DownStep; x++)
7252  {
7253  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7254  }
7255  Display->Update();
7256  Utilities->CallLogPop(1944);
7257  return;
7258  }
7259 
7260  else // ver track element
7261  {
7262  // find leftmost LC, opening them all (to trains) in turn
7263  int LStep = 0;
7264  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
7265  {
7266  LStep--;
7267  }
7268  LStep++;
7269  // now find rightmost LC, opening them all (to trains) in turn
7270  int RStep = 1;
7271  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
7272  {
7273  RStep++;
7274  }
7275  RStep--;
7276  // now plot graphics, LStep is smallest & RStep largest
7277  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
7278  {
7279  if(!Manual)
7280  {
7281  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
7282  }
7283  else
7284  {
7285  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
7286  }
7287  }
7288  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
7289  {
7290  if(!Manual)
7291  {
7292  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7293  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7294  }
7295  else
7296  {
7297  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7298  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7299  }
7300  }
7301  else // at least one plain graphic
7302  {
7303  if(!Manual)
7304  {
7305  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
7306  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
7307  for(int x = (LStep + 1); x < RStep; x++)
7308  {
7309  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
7310  }
7311  }
7312  else
7313  {
7314  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
7315  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
7316  for(int x = (LStep + 1); x < RStep; x++)
7317  {
7318  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
7319  }
7320  }
7321  }
7322  // set markers
7323  for(int x = LStep; x <= RStep; x++)
7324  {
7325  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
7326  }
7327  Disp->Update();
7328  Utilities->CallLogPop(1945);
7329  return;
7330  }
7331 }
7332 
7333 // ---------------------------------------------------------------------------
7334 
7335 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
7336 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7337 {
7338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
7339  AnsiString(VLoc));
7340  if(!IsLCAtHV(9, HLoc, VLoc))
7341  {
7342  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
7343  }
7344  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7345  {
7346  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
7347  }
7348 // check for adjacent LCs & if so close (to trains)
7349  if(BaseElementSpeedTag == 1) // hor track element
7350  {
7351  // find topmost LC, closing them all (to trains) in turn
7352  int UpStep = 0;
7353  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7354  {
7355  UpStep--;
7356  }
7357  UpStep++;
7358  // now find bottommost LC, opening them all (to trains) in turn
7359  int DownStep = 1;
7360  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
7361  {
7362  DownStep++;
7363  }
7364  DownStep--;
7365  // now plot graphics, UpStep is smallest & DownStep largest
7366  for(int x = UpStep; x < (DownStep + 1); x++)
7367  {
7368  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
7369  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
7370  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7371  }
7372  Disp->Update();
7373  Utilities->CallLogPop(1959);
7374  return;
7375  }
7376 
7377  else // ver track element
7378  {
7379  // find leftmost LC, closing them all (to trains) in turn
7380  int LStep = 0;
7381  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
7382  {
7383  LStep--;
7384  }
7385  LStep++;
7386  // now find rightmost LC, opening them all (to trains) in turn
7387  int RStep = 1;
7388  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
7389  {
7390  RStep++;
7391  }
7392  RStep--;
7393  // now plot graphics, LStep is smallest & RStep largest
7394  for(int x = LStep; x < (RStep + 1); x++)
7395  {
7396  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7397  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
7398  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7399  }
7400  Disp->Update();
7401  Utilities->CallLogPop(1960);
7402  return;
7403  }
7404 }
7405 
7406 // ---------------------------------------------------------------------------
7407 
7408 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
7409 // closed to trains
7410 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
7411 {
7412  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
7413  AnsiString(HLoc) + "," + AnsiString(VLoc));
7414  if(!IsLCAtHV(34, HLoc, VLoc))
7415  {
7416  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7417  }
7418  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
7419  {
7420  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
7421  }
7422  TTrackElement TE;
7423 
7424 // check for adjacent LCs & if so close (to trains)
7425  if(BaseElementSpeedTag == 1) // hor track element
7426  {
7427  // find topmost LC, closing them all (to trains) in turn
7428  int UpStep = 0;
7429  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7430  {
7431  UpStep--;
7432  }
7433  UpStep++;
7434  // now find bottommost LC, opening them all (to trains) in turn
7435  int DownStep = 1;
7436  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
7437  {
7438  DownStep++;
7439  }
7440  DownStep--;
7441  // now plot graphics, UpStep is smallest & DownStep largest
7442  for(int x = UpStep; x <= DownStep; x++)
7443  {
7444  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7445  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7446  }
7447  Display->Update();
7448  Utilities->CallLogPop(1946);
7449  return;
7450  }
7451 
7452  else // ver track element
7453  {
7454  // find leftmost LC, closing them all (to trains) in turn
7455  int LStep = 0;
7456  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7457  {
7458  LStep--;
7459  }
7460  LStep++;
7461  // now find rightmost LC, opening them all (to trains) in turn
7462  int RStep = 1;
7463  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7464  {
7465  RStep++;
7466  }
7467  RStep--;
7468  // now plot graphics, LStep is smallest & RStep largest
7469  for(int x = LStep; x <= RStep; x++)
7470  {
7471  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7472  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7473  }
7474  Display->Update();
7475  Utilities->CallLogPop(1947);
7476  return;
7477  }
7478 }
7479 
7480 // ---------------------------------------------------------------------------
7481 
7482 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7483 {
7484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7485  Graphics::TBitmap *RouteGraphic;
7486  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7487 
7488  if(BaseElementSpeedTag == 1)
7489  {
7490  if(TypeOfRoute == 1)
7491  {
7492  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7493  }
7494  else if(TypeOfRoute == 0)
7495  {
7496  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7497  }
7498  else //manual
7499  {
7500  RouteGraphic = BaseGraphic;
7501  }
7502  if(State == Raising)
7503  {
7504  RouteGraphic = BaseGraphic;
7505  }
7506  }
7507  else
7508  {
7509  BaseGraphic = RailGraphics->gl2;
7510  if(TypeOfRoute == 1)
7511  {
7512  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7513  }
7514  else if(TypeOfRoute == 0)
7515  {
7516  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7517  }
7518  else
7519  {
7520  RouteGraphic = BaseGraphic; //manual
7521  }
7522  if(State == Raising)
7523  {
7524  RouteGraphic = BaseGraphic;
7525  }
7526  }
7527  int UpStep = 0;
7528 
7529  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7530  {
7531  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7532  if(UpStep == 0)
7533  {
7534  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7535  }
7536  else
7537  {
7538  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7539  }
7540  UpStep--;
7541  }
7542 // now find bottommost LC, opening them all (to trains) in turn
7543  int DownStep = 1;
7544 
7545  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7546  {
7547  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7548  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7549  DownStep++;
7550  }
7551  int LeftStep = 0;
7552 
7553  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7554  {
7555  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7556  if(LeftStep == 0)
7557  {
7558  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7559  }
7560  else
7561  {
7562  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7563  }
7564  LeftStep--;
7565  }
7566 // now find rightmost LC, opening them all (to trains) in turn
7567  int RightStep = 1;
7568 
7569  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7570  {
7571  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7572  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7573  RightStep++;
7574  }
7575  Disp->Update();
7576  Utilities->CallLogPop(1914);
7577 }
7578 
7579 // ---------------------------------------------------------------------------
7580 
7581 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7582 {
7583 // return false for no LC there, flashing or a closed (to trains) LC
7584  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7585  bool FoundFlag;
7586  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7587 
7588  if(!FoundFlag)
7589  {
7590  Utilities->CallLogPop(1898);
7591  return(false);
7592  }
7593  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7594  {
7595  Utilities->CallLogPop(1899);
7596  return(false);
7597  }
7598  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7599  {
7600  Utilities->CallLogPop(1900);
7601  return(true);
7602  }
7603  Utilities->CallLogPop(1901);
7604  return(false);
7605 }
7606 
7607 // ---------------------------------------------------------------------------
7608 
7609 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7610 {
7611 // return false for no LC there, flashing LC or open (to trains) LC
7612  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7613  bool FoundFlag;
7614  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7615 
7616  if(!FoundFlag)
7617  {
7618  Utilities->CallLogPop(1922);
7619  return(false);
7620  }
7621  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7622  {
7623  Utilities->CallLogPop(1923);
7624  return(false);
7625  }
7626  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7627  {
7628  Utilities->CallLogPop(1924);
7629  return(true);
7630  }
7631  Utilities->CallLogPop(1925);
7632  return(false);
7633 }
7634 
7635 // ---------------------------------------------------------------------------
7636 
7637 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7638 {
7639 // return true for barrier in process of moving
7640  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7641  bool FoundFlag;
7642  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7643 
7644  if(!FoundFlag)
7645  {
7646  Utilities->CallLogPop(1918);
7647  return(false);
7648  }
7649  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7650  {
7651  Utilities->CallLogPop(1919);
7652  return(false);
7653  }
7654  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7655  {
7656  Utilities->CallLogPop(1920);
7657  return(true);
7658  }
7659  Utilities->CallLogPop(1921);
7660  return(false);
7661 }
7662 
7663 // ---------------------------------------------------------------------------
7664 
7665 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7666 {
7667 // return true for an LC at H&V
7668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7669  bool FoundFlag;
7670  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7671 
7672  if(!FoundFlag)
7673  {
7674  Utilities->CallLogPop(1902);
7675  return(false);
7676  }
7677  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7678  {
7679  Utilities->CallLogPop(1903);
7680  return(false);
7681  }
7682  Utilities->CallLogPop(1904);
7683  return(true);
7684 }
7685 
7686 // ---------------------------------------------------------------------------
7687 
7688 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7689 {
7690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7691  AnsiString(Attr));
7692  bool FoundFlag;
7693  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7694 
7695  if(!FoundFlag)
7696  {
7697  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7698  }
7699  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7700  {
7701  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7702  }
7703  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7704  Utilities->CallLogPop(1905);
7705  return;
7706 }
7707 
7708 // ---------------------------------------------------------------------------
7709 
7711 {
7712  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7713  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7714  {
7715  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7716  if(InactiveTrackElement.TrackType == LevelCrossing)
7717  {
7718  InactiveTrackElementAt(141, x).Attribute = 0;
7719  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7720  }
7721  }
7722  Utilities->CallLogPop(1913);
7723  return;
7724 }
7725 
7726 // ---------------------------------------------------------------------------
7727 
7728 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7729 {
7730 // return true if there is either a route set or being set on any element or a train on any element
7731  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7732  "," + AnsiString(VLoc));
7733 
7734  THVPair TrackMapKeyPair;
7735  TTrack::TTrackMapIterator TrackMapPtr;
7736  int DummyRouteNumber;
7737 
7738  TrainPresent = false;
7739 // find topmost LC, checking each for routes & trains
7740  int UpStep = 0;
7741 
7742  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7743  {
7744  TrackMapKeyPair.first = HLoc;
7745  TrackMapKeyPair.second = VLoc + UpStep;
7746  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7747  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7748  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7749  {
7750  Utilities->CallLogPop(1932);
7751  return(true);
7752  }
7753  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7754  {
7755  TrainPresent = true;
7756  Utilities->CallLogPop(1933);
7757  return(true);
7758  }
7759  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7760  {
7761  Utilities->CallLogPop(2274);
7762  return(true);
7763  }
7764  UpStep--;
7765  }
7766 // now find bottommost LC, opening them all (to trains) in turn
7767  int DownStep = 1;
7768 
7769  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7770  {
7771  TrackMapKeyPair.first = HLoc;
7772  TrackMapKeyPair.second = VLoc + DownStep;
7773  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7774  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7775  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7776  {
7777  Utilities->CallLogPop(1934);
7778  return(true);
7779  }
7780  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7781  {
7782  TrainPresent = true;
7783  Utilities->CallLogPop(1935);
7784  return(true);
7785  }
7786  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7787  {
7788  Utilities->CallLogPop(2275);
7789  return(true);
7790  }
7791  DownStep++;
7792  }
7793 // find leftmost LC
7794  int LeftStep = 0;
7795 
7796  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7797  {
7798  TrackMapKeyPair.first = HLoc + LeftStep;
7799  TrackMapKeyPair.second = VLoc;
7800  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7801  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7802  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7803  {
7804  Utilities->CallLogPop(1936);
7805  return(true);
7806  }
7807  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7808  {
7809  TrainPresent = true;
7810  Utilities->CallLogPop(1937);
7811  return(true);
7812  }
7813  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7814  {
7815  Utilities->CallLogPop(2276);
7816  return(true);
7817  }
7818  LeftStep--;
7819  }
7820 // now find rightmost LC, opening them all (to trains) in turn
7821  int RightStep = 1;
7822 
7823  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7824  {
7825  TrackMapKeyPair.first = HLoc + RightStep;
7826  TrackMapKeyPair.second = VLoc;
7827  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7828  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7829  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7830  {
7831  Utilities->CallLogPop(1938);
7832  return(true);
7833  }
7834  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7835  {
7836  TrainPresent = true;
7837  Utilities->CallLogPop(1939);
7838  return(true);
7839  }
7840  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7841  {
7842  Utilities->CallLogPop(2277);
7843  return(true);
7844  }
7845  RightStep++;
7846  }
7847  Utilities->CallLogPop(1940);
7848  return(false);
7849 }
7850 
7851 // ---------------------------------------------------------------------------
7852 
7853 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7854 {
7855  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7856  for(unsigned int x = 0; x < SearchVector.size(); x++)
7857  {
7858  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7859  {
7860  Utilities->CallLogPop(2278);
7861  return(true);
7862  }
7863  }
7864  Utilities->CallLogPop(2279);
7865  return(false);
7866 }
7867 
7868 // ---------------------------------------------------------------------------
7869 
7870 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7871 {
7872  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7873  AnsiString(HLoc) + "," + AnsiString(VLoc));
7874  if(!IsLCAtHV(60, HLoc, VLoc))
7875  {
7876  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7877  }
7878 
7879 // check for adjacent LCs
7880  // find topmost LC
7881  int UpStep = 0;
7882  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7883  {
7884  UpStep--;
7885  }
7886  UpStep++;
7887  // now find bottommost LC, opening them all (to trains) in turn
7888  int DownStep = 1;
7889  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7890  {
7891  DownStep++;
7892  }
7893  DownStep--;
7894  // now plot graphics, UpStep is smallest & DownStep largest
7895  for(int x = UpStep; x <= DownStep; x++)
7896  {
7897  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7898  }
7899 
7900  // find leftmost LC, closing them all (to trains) in turn
7901  int LStep = 0;
7902  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7903  {
7904  LStep--;
7905  }
7906  LStep++;
7907  // now find rightmost LC, opening them all (to trains) in turn
7908  int RStep = 1;
7909  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7910  {
7911  RStep++;
7912  }
7913  RStep--;
7914  // now plot graphics, LStep is smallest & RStep largest
7915  for(int x = LStep; x <= RStep; x++)
7916  {
7917  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7918  }
7919  Display->Update();
7920  Utilities->CallLogPop(2315);
7921  return;
7922 }
7923 
7924 // ---------------------------------------------------------------------------
7925 
7926 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7927 {
7928  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7929  if(TrackElement.TrackType != Points)
7930  {
7931  throw Exception("Error, Wrong track type in GetFilletGraphic");
7932  }
7933  if(TrackElement.SpeedTag < 28)
7934  {
7935  Utilities->CallLogPop(521);
7936  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7937  }
7938  else if(TrackElement.SpeedTag < 132)
7939  {
7940  Utilities->CallLogPop(522);
7941 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7942  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7943  }
7944  else
7945  {
7946  Utilities->CallLogPop(1537);
7947  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7948  }
7949 }
7950 
7951 // ---------------------------------------------------------------------------
7952 
7954 {
7955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDsAndFailedPointOrigSpeedLimits");
7956  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7957  {
7958  TrackElementAt(1351, x).TrainIDOnElement = -1;
7961  }
7962  Utilities->CallLogPop(1342);
7963 }
7964 
7965 // ---------------------------------------------------------------------------
7966 
7967 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7968 /*
7969  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7970 */
7971 {
7972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7973  AnsiString(ScreenPosV));
7974  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7975  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7976 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7977  Utilities->CallLogPop(535);
7978 }
7979 
7980 // ---------------------------------------------------------------------------
7981 
7982 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7983 /*
7984  Converts the screen position to the true (without offsets) position
7985 */
7986 {
7987  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7988  AnsiString(ScreenPosV));
7989  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7990  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7991  Utilities->CallLogPop(536);
7992 }
7993 
7994 // ---------------------------------------------------------------------------
7995 
7996 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7997 {
7998  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7999  AnsiString(VPosTrue));
8000  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
8001  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
8002  Utilities->CallLogPop(537);
8003 }
8004 
8005 // ---------------------------------------------------------------------------
8006 
8007 void TTrack::CheckMapAndTrack(int Caller) // test
8008 {
8009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
8010  int Zeroes = 0;
8011  bool FoundFlag;
8012 
8013  for(unsigned int a = 0; a < TrackVector.size(); a++)
8014  {
8015  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
8016  if(CheckElement.SpeedTag == 0)
8017  {
8018  Zeroes++; // zeroed elements not saved in map
8019  }
8020  else
8021  {
8022  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
8023  if(!FoundFlag)
8024  {
8025  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
8026  " in TrackMap, Caller=" + (AnsiString)Caller);
8027  }
8028  if(MapVecPos != (int)a)
8029  {
8030  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
8031  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
8032  (AnsiString)Caller);
8033  }
8034  }
8035  }
8036  if(TrackVector.size() != (TrackMap.size() + Zeroes))
8037  {
8038  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
8039  " Caller=" + (AnsiString)Caller);
8040  }
8041  Utilities->CallLogPop(538);
8042  return;
8043 }
8044 
8045 // ---------------------------------------------------------------------------
8046 
8047 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
8048 {
8049  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
8050  bool FoundFlag;
8051  TIMPair InactivePair;
8052 
8053  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
8054  {
8055  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
8056  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
8057  if(!FoundFlag)
8058  {
8059  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
8060  " in InactiveMap, Caller=" + (AnsiString)Caller);
8061  }
8062  if((InactivePair.first != a) && (InactivePair.second != a))
8063  {
8064  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
8065  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
8066  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
8067  }
8068  }
8069  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
8070  {
8071  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
8072  " Caller=" + (AnsiString)Caller);
8073  }
8074  Utilities->CallLogPop(539);
8075 }
8076 
8077 // ---------------------------------------------------------------------------
8078 
8079 void TTrack::CheckGapMap(int Caller) // test
8080 {
8081  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
8082  int Position1, Position2;
8083  TTrackElement TrackElement1, TrackElement2;
8084  TGapMapIterator GapMapPtr;
8085 
8086  if(!GapMap.empty())
8087  {
8088  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
8089  {
8090  int HLoc1 = GapMapPtr->first.first;
8091  int VLoc1 = GapMapPtr->first.second;
8092  int HLoc2 = GapMapPtr->second.first;
8093  int VLoc2 = GapMapPtr->second.second;
8094  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
8095  {
8096  throw Exception("Failed to find H & V for gap1, GapMap in error");
8097  }
8098  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
8099  {
8100  throw Exception("Failed to find H & V for gap2, GapMap in error");
8101  }
8102  if(TrackElementAt(17, Position1).TrackType != GapJump)
8103  {
8104  throw Exception("Element at Pos1 not a gap, GapMap in error");
8105  }
8106  if(TrackElementAt(18, Position2).TrackType != GapJump)
8107  {
8108  throw Exception("Element at Pos2 not a gap, GapMap in error");
8109  }
8110  }
8111  }
8112  unsigned int GapCount = 0;
8113 
8114  for(unsigned int a = 0; a < TrackVector.size(); a++)
8115  {
8116  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
8117  if(CheckElement.TrackType == GapJump)
8118  {
8119  GapCount++;
8120  }
8121  }
8122  if((GapMap.size() * 2) != GapCount)
8123  {
8124  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
8125  (AnsiString)Caller);
8126  }
8127  Utilities->CallLogPop(540);
8128 }
8129 
8130 // ---------------------------------------------------------------------------
8131 
8132 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
8133 {
8134  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
8135  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
8136  {
8137  if(TrackFinished)
8138  {
8139  throw Exception("Error - TrackFinished with erase element still present");
8140  }
8141  Utilities->CallLogPop(541);
8142  return; // erased element, can't set ID
8143  }
8144  AnsiString IDString;
8145 
8146  if(TrackElement.HLoc < 0)
8147  {
8148  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
8149  }
8150  else
8151  {
8152  IDString = AnsiString(TrackElement.HLoc) + "-";
8153  }
8154  if(TrackElement.VLoc < 0)
8155  {
8156  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
8157  }
8158  else
8159  {
8160  IDString += AnsiString(TrackElement.VLoc);
8161  }
8162  TrackElement.ElementID = IDString;
8163  Utilities->CallLogPop(542);
8164 }
8165 
8166 // ---------------------------------------------------------------------------
8167 
8168 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
8169 {
8170 // e.g. "8-13", "00008-13", "N43-N127", etc
8171  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString," + String); //String was inside " marks, corrected at v2.13.0
8172  int DelimPos;
8173 try //try..catch added at v2.13.0 following Amon Sadler's error file received on 24/03/22, had N-113-5 rather than N113-5
8174  {
8175  for(int x = 1; x < String.Length() + 1; x++)
8176  {
8177  if(String.IsDelimiter("-", x))
8178  {
8179  DelimPos = x;
8180  break;
8181  }
8182  if(x == String.Length())
8183  {
8184  if(GiveMessages)
8185  {
8186  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
8187  }
8188  Utilities->CallLogPop(543);
8189  return(-1);
8190  }
8191  }
8192  if(DelimPos == 1)
8193  {
8194  if(GiveMessages)
8195  {
8196  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
8197  }
8198  Utilities->CallLogPop(544);
8199  return(-1);
8200  }
8201  if(DelimPos == String.Length())
8202  {
8203  if(GiveMessages)
8204  {
8205  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
8206  }
8207  Utilities->CallLogPop(545);
8208  return(-1);
8209  }
8210  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
8211  {
8212  if(GiveMessages)
8213  {
8214  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
8215  }
8216  Utilities->CallLogPop(1508);
8217  return(-1);
8218  }
8219  int HLoc, VLoc;
8220 
8221  if(String.SubString(1, 1) != "N")
8222  {
8223  for(int x = 1; x < DelimPos; x++)
8224  {
8225  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8226  {
8227  if(GiveMessages)
8228  {
8229  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8230  }
8231  Utilities->CallLogPop(546);
8232  return(-1);
8233  }
8234  }
8235  }
8236  if(String.SubString(1, 1) == "N")
8237  {
8238  for(int x = 2; x < DelimPos; x++)
8239  {
8240  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8241  {
8242  if(GiveMessages)
8243  {
8244  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
8245  }
8246  Utilities->CallLogPop(763);
8247  return(-1);
8248  }
8249  }
8250  }
8251  if(String.SubString(1, 1) == "N")
8252  {
8253  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
8254  }
8255  else
8256  {
8257  HLoc = String.SubString(1, DelimPos - 1).ToInt();
8258  }
8259  if(String.SubString(DelimPos + 1, 1) != "N")
8260  {
8261  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
8262  {
8263  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8264  {
8265  if(GiveMessages)
8266  {
8267  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8268  }
8269  Utilities->CallLogPop(547);
8270  return(-1);
8271  }
8272  }
8273  }
8274  if(String.SubString(DelimPos + 1, 1) == "N")
8275  {
8276  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
8277  {
8278  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
8279  {
8280  if(GiveMessages)
8281  {
8282  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
8283  }
8284  Utilities->CallLogPop(764);
8285  return(-1);
8286  }
8287  }
8288  }
8289  if(String.SubString(DelimPos + 1, 1) == "N")
8290  {
8291  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
8292  }
8293  else
8294  {
8295  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
8296  }
8297  THVPair HVPair(HLoc, VLoc);
8298  TTrackMapIterator TrackMapPtr;
8299 
8300  TrackMapPtr = TrackMap.find(HVPair);
8301  if(TrackMapPtr == TrackMap.end())
8302  {
8303  if(GiveMessages)
8304  {
8305  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
8306  }
8307  Utilities->CallLogPop(548);
8308  return(-1);
8309  }
8310  Utilities->CallLogPop(549);
8311  return(TrackMapPtr->second);
8312  }
8313  catch(const Exception &e) //non-error catch - catches any errors not already caught above
8314  //(added at v2.13.0 following Amon Sadler's error file received on 24/03/22), had N-113-5 rather than N113-5
8315  {
8316  ShowMessage("Syntax error in track element identifier: <" + String + ">");
8317  Utilities->CallLogPop(2481);
8318  return(-1);
8319  }
8320 }
8321 
8322 // ---------------------------------------------------------------------------
8323 
8324 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
8325 /*
8326  True for linked properly at both ends
8327 */
8328 {
8329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
8330  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
8331  int HLoc = TrackElement.HLoc;
8332  int VLoc = TrackElement.VLoc;
8333 
8334  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
8335  {
8336  Utilities->CallLogPop(1821);
8337  return(false);
8338  }
8339  if(TrackElement.SpeedTag == 129) // vertical footbridge
8340  {
8341  // check top connection
8342  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
8343  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
8344  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
8345  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
8346  {
8347  Utilities->CallLogPop(550);
8348  return(false);
8349  }
8350  // check bottom connection
8351  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
8352  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
8353  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
8354  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
8355  {
8356  Utilities->CallLogPop(551);
8357  return(false);
8358  }
8359  }
8360  if(TrackElement.SpeedTag == 145) // vertical underpass
8361  {
8362  // check top connection
8363  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
8364  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
8365  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
8366  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
8367  {
8368  Utilities->CallLogPop(2114);
8369  return(false);
8370  }
8371  // check bottom connection
8372  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
8373  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
8374  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
8375  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
8376  {
8377  Utilities->CallLogPop(2115);
8378  return(false);
8379  }
8380  }
8381  if(TrackElement.SpeedTag == 130) // hor footbridge
8382  {
8383  // check left connection
8384  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
8385  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
8386  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
8387  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
8388  {
8389  Utilities->CallLogPop(552);
8390  return(false);
8391  }
8392  // check right connection
8393  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
8394  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
8395  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
8396  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
8397  {
8398  Utilities->CallLogPop(553);
8399  return(false);
8400  }
8401  }
8402  if(TrackElement.SpeedTag == 146) // hor u'pass
8403  {
8404  // check left connection
8405  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
8406  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
8407  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
8408  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
8409  {
8410  Utilities->CallLogPop(2116);
8411  return(false);
8412  }
8413  // check right connection
8414  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
8415  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
8416  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
8417  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
8418  {
8419  Utilities->CallLogPop(2117);
8420  return(false);
8421  }
8422  }
8423  Utilities->CallLogPop(554);
8424  return(true);
8425 }
8426 
8427 // ---------------------------------------------------------------------------
8428 
8429 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8430 /*
8431  return true if the SpeedTag present in the map at H & V
8432 */
8433 {
8434  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8435  AnsiString(SpeedTag));
8436  if(InactiveTrack2MultiMap.empty())
8437  {
8438  Utilities->CallLogPop(555);
8439  return(false);
8440  }
8441  THVPair HVPair(HLoc, VLoc);
8443  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
8444  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
8445 
8446  if(HVRange.first == HVRange.second)
8447  {
8448  Utilities->CallLogPop(556);
8449  return(false);
8450  }
8451  else
8452  {
8453  HVIt1 = HVRange.first;
8454  }
8455  TTrackElement Temp1, Temp2; // test
8456 
8457  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8458  if(--HVRange.second != HVRange.first)
8459  {
8460  HVIt2 = HVRange.second;
8461  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8462  }
8463  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8464  HVIt2->second).SpeedTag == SpeedTag)))
8465  {
8466  Utilities->CallLogPop(557);
8467  return(true);
8468  }
8469  else
8470  {
8471  Utilities->CallLogPop(558);
8472  return(false);
8473  }
8474 }
8475 
8476 // ---------------------------------------------------------------------------
8477 
8478 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8479 /*
8480  return true if the SpeedTag present in the map at H & V
8481 */
8482 {
8483  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8484  AnsiString(SpeedTag));
8485  if(TrackMap.empty())
8486  {
8487  Utilities->CallLogPop(559);
8488  return(false);
8489  }
8490  THVPair HVPair(HLoc, VLoc);
8491  TTrackMapIterator End = TrackMap.end();
8492  TTrackMapIterator It = End;
8493 
8494  It = TrackMap.find(HVPair);
8495  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8496  {
8497  Utilities->CallLogPop(560);
8498  return(true);
8499  }
8500  else
8501  {
8502  Utilities->CallLogPop(561);
8503  return(false);
8504  }
8505 }
8506 
8507 // ---------------------------------------------------------------------------
8508 
8509 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8510 {
8511 /*
8512  General:
8513  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8514  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8515  a NamedNonStationLocation.
8516  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8517  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8518  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8519  platform at that location).
8520 
8521  Linked named location elements are those explained in TTrack::TTrack()
8522 
8523  Detail:
8524  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8525  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8526  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8527  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8528  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8529  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8530 
8531  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8532  this function a single element should be in the List (normally from the user's selection but can also be from
8533  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8534  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8535  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8536  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8537  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8538  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8539  moves them into the Map. At the end all linked elements are in the Map.
8540 
8541  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8542  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8543  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8544 */
8545 
8546 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8547 // Display->FileDiagnostics(TestString);//test
8548 
8549  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8550  AnsiString TestString1, TestString2; // test
8551 
8552  Track->LNDone2MultiMap.clear();
8553  if(LNPendingList.size() != 1)
8554  {
8555  throw Exception("LNPendingList size not 1 on entry");
8556  }
8557  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8558  bool FoundFlag = false, ErasedFlag = false;
8559  while(!LNPendingList.empty())
8560  {
8561  CurrentElementNumber = LNPendingList.front();
8562  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8563  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8564  int H = CurrentElement->HLoc;
8565  int V = CurrentElement->VLoc;
8566  int Tag = CurrentElement->SpeedTag;
8567  if(Tag == 76) // top plat
8568  {
8569  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8570  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8571  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8572  for(int x = 0; x < 25; x++)
8573  {
8574  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8575  {
8576  LNPendingList.insert(LNPendingList.end(), NewElement);
8577  }
8578  }
8579  }
8580  else if(Tag == 77) // bot plat
8581  {
8582  for(int x = 0; x < 25; x++)
8583  {
8584  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8585  {
8586  LNPendingList.insert(LNPendingList.end(), NewElement);
8587  }
8588  }
8589  }
8590  else if(Tag == 78) // l plat
8591  {
8592  for(int x = 0; x < 25; x++)
8593  {
8594  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8595  {
8596  LNPendingList.insert(LNPendingList.end(), NewElement);
8597  }
8598  }
8599  }
8600  else if(Tag == 79) // r plat
8601  {
8602  for(int x = 0; x < 25; x++)
8603  {
8604  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8605  {
8606  LNPendingList.insert(LNPendingList.end(), NewElement);
8607  }
8608  }
8609  }
8610  else if(Tag == 96) // conc
8611  {
8612  for(int x = 0; x < 28; x++)
8613  {
8614  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8615  {
8616  LNPendingList.insert(LNPendingList.end(), NewElement);
8617  }
8618  }
8619  }
8620  else if(Tag == 129) // vert footbridge
8621  {
8622  for(int x = 0; x < 8; x++)
8623  {
8624  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8625  {
8626  LNPendingList.insert(LNPendingList.end(), NewElement);
8627  }
8628  }
8629  }
8630  else if(Tag == 130) // hor footbridge
8631  {
8632  for(int x = 0; x < 8; x++)
8633  {
8634  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8635  {
8636  LNPendingList.insert(LNPendingList.end(), NewElement);
8637  }
8638  }
8639  }
8640  else if(Tag == 131) // named location
8641  {
8642  for(int x = 0; x < 4; x++)
8643  {
8644  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8645  {
8646  LNPendingList.insert(LNPendingList.end(), NewElement);
8647  }
8648  }
8649  int TVPos = GetVectorPositionFromTrackMap(67, H, V, FoundFlag); //deal with gaps, added at v2.18.0
8650  {
8651  if(FoundFlag && TrackElementAt(1585, TVPos).TrackType == GapJump)
8652  {
8653  int GJTVPos = TrackElementAt(1586, TVPos).Conn[0];
8654  if(GJTVPos > -1)
8655  {
8656  int HLoc = TrackElementAt(1587, GJTVPos).HLoc;
8657  int VLoc = TrackElementAt(1588, GJTVPos).VLoc;
8658  bool FoundFlag2 = false;
8659  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(33, HLoc, VLoc, FoundFlag2);
8660  if(FoundFlag2)
8661  {
8662  if(Track->InactiveTrackElementAt(1410, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
8663  {
8664  if(!ElementInLNDone2MultiMap(5, IMPair.first) && !ElementInLNPendingList(6, IMPair.first))
8665  {
8666  LNPendingList.insert(LNPendingList.end(), IMPair.first);
8667  }
8668  }
8669  }
8670  }
8671  }
8672  }
8673  }
8674  else if(Tag == 145) // v u'pass
8675  {
8676  for(int x = 0; x < 8; x++)
8677  {
8678  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8679  {
8680  LNPendingList.insert(LNPendingList.end(), NewElement);
8681  }
8682  }
8683  }
8684  else if(Tag == 146) // h u'pass
8685  {
8686  for(int x = 0; x < 8; x++)
8687  {
8688  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8689  {
8690  LNPendingList.insert(LNPendingList.end(), NewElement);
8691  }
8692  }
8693  }
8694  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8695 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8696  if(AddingElements)
8697  {
8698  int HPos, VPos; // not used but needed for FindText function
8699  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8700  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8701  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8702  {
8703  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8704  if((ExistingName != "") && (ExistingName != LocationName))
8705  {
8706  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8707  {
8708  } // name not in LocationNameMultiMap, so don't erase from TextVector
8709  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8710  {
8711  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8712  {
8713  ;
8714  } // condition not used
8715 
8716  }
8717  }
8718  }
8719  }
8720  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8721  // track at that loc
8722  THVPair HVPair(H, V);
8723  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8724  LNDone2MultiMapEntry.first = HVPair;
8725  LNDone2MultiMapEntry.second = LNPendingList.front();
8726  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8727  LNPendingList.erase(LNPendingList.begin());
8728  }
8729 
8730 // search all name multimap for same name where corresponding active elements don't appear in
8731 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8732 
8733  TLocationNameMultiMapIterator SNIterator;
8734  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8735 
8736  if(SNRange.first != SNRange.second)
8737  {
8738  SNRange.first--; // now pointing to before the first
8739  SNRange.second--; // now pointing to the last
8740  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8741  {
8742  // Same elements are in Done map as in name map
8743  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8744  {
8745  ErasedFlag = true;
8746  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8747  TVIt->LocationName = "";
8748  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8749  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8750  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8751  {
8752  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8753  if(FoundFlag)
8754  {
8755  TrackElementAt(20, Position).LocationName = "";
8756  TrackElementAt(21, Position).ActiveTrackElementName = "";
8757  }
8758  }
8759  // erase name in name map
8760 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8761  }
8762  }
8763  }
8764  if(ErasedFlag)
8765  {
8767  }
8768  if(TrackFinished)
8769  {
8772  }
8773 // set here as well as in LinkTrack so don't have to link track just because a name added
8774 // if track not finished then will be set when track validated
8775 
8776 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8777 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8778 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8779 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8780 // so the error would be seen.
8781 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8782  std::pair<AnsiString, char>TempMapPair;
8783 
8784  ContinuationNameMap.clear();
8785  for(int x = 0; x < Track->TrackVectorSize(); x++)
8786  {
8787  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8788  {
8789  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8790  TempMapPair.second = 'x'; // unused
8791  ContinuationNameMap.insert(TempMapPair);
8792  }
8793  }
8794 //end of addition
8795  CheckLocationNameMultiMap(1); // test
8796  Utilities->CallLogPop(562);
8797 }
8798 
8799 // ---------------------------------------------------------------------------
8800 
8801 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8802 /*
8803  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8804  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8805 */
8806 {
8807  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8808  AnsiString(SpeedTag));
8809  if(!NamedLocationElementAt(2, HLoc, VLoc))
8810  {
8811  Utilities->CallLogPop(948);
8812  return(false);
8813  }
8814  bool FoundFlag;
8815  int Position = -1;
8816  TIMPair IMPair;
8817 
8818  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8819  {
8820  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8821  if(FoundFlag)
8822  {
8823  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8824  {
8825  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8826  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8827  // don't allow duplicates in either list, or processing takes a lot longer
8828  {
8829  FoundElement = MapPos;
8830  Utilities->CallLogPop(563);
8831  return(true);
8832  }
8833  }
8834  }
8835  }
8836  else
8837  {
8838  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8839  if(FoundFlag)
8840  {
8841  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8842  {
8843  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8844  {
8845  FoundElement = IMPair.first;
8846  Utilities->CallLogPop(564);
8847  return(true);
8848  }
8849  }
8850  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8851  {
8852  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8853  {
8854  FoundElement = IMPair.second;
8855  Utilities->CallLogPop(565);
8856  return(true);
8857  }
8858  }
8859  }
8860  }
8861  Utilities->CallLogPop(566);
8862  return(false);
8863 }
8864 
8865 // ---------------------------------------------------------------------------
8866 
8867 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8868 /*
8869  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8870  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8871  with the new name
8872 */
8873 {
8874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8875  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8876 
8877  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8878  int HLoc = TrackElement->HLoc;
8879  int VLoc = TrackElement->VLoc;
8880  bool FoundFlag;
8881 
8882  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8883  // only have timetable names for adjacent platforms & named locations
8884  {
8885  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8886  if(FoundFlag)
8887  {
8888  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8889  }
8890  }
8891  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8892 
8893  if(ErrorString != "")
8894  {
8895  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8896  }
8897  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8898  CheckLocationNameMultiMap(2); // test
8899  Utilities->CallLogPop(567);
8900 }
8901 
8902 // ---------------------------------------------------------------------------
8903 
8904 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8905 /*
8906  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8907 */
8908 {
8909  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8910  if(LNDone2MultiMap.empty())
8911  {
8912  Utilities->CallLogPop(568);
8913  return(false);
8914  }
8915  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8916 
8917  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8918  {
8919  if(LNDone2MultiMapIterator->second == MapPos)
8920  {
8921  Utilities->CallLogPop(569);
8922  return(true);
8923  }
8924  }
8925  Utilities->CallLogPop(570);
8926  return(false);
8927 }
8928 
8929 // ---------------------------------------------------------------------------
8930 
8931 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8932 /*
8933  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8934 */
8935 {
8936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8937  if(LNPendingList.empty())
8938  {
8939  Utilities->CallLogPop(571);
8940  return(false);
8941  }
8942  TLNPendingListIterator LNPendingListIterator;
8943 
8944  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8945  {
8946  if(*LNPendingListIterator == MapPos)
8947  {
8948  Utilities->CallLogPop(572);
8949  return(true);
8950  }
8951  }
8952  Utilities->CallLogPop(573);
8953  return(false);
8954 }
8955 
8956 // ---------------------------------------------------------------------------
8957 
8958 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8959 /*
8960  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8961 */
8962 {
8963  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8964  THVPair HVPair(HLoc, VLoc);
8965  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8966  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8967 
8968  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8969  {
8970  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8971  {
8972  Utilities->CallLogPop(574);
8973  return(true);
8974  }
8975  }
8976  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8977  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8978  {
8979  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8980  {
8981  Utilities->CallLogPop(575);
8982  return(true);
8983  }
8984  }
8985  Utilities->CallLogPop(576);
8986  return(false);
8987 }
8988 
8989 // ---------------------------------------------------------------------------
8990 
8991 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8992 {
8993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8994  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8995  {
8996  Utilities->CallLogPop(1953);
8997  return(true);
8998  }
8999  Utilities->CallLogPop(1954);
9000  return(false);
9001 }
9002 
9003 // ---------------------------------------------------------------------------
9004 
9005 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
9006 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
9007 //program and used when try to save as a .rly file
9008 {
9009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
9012  if(LocationNameMultiMap.empty()) //no names so no duplicates
9013  {
9014  Utilities->CallLogPop(2254);
9015  return(false);
9016  }
9017  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
9018  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
9019  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
9020  {
9022  {
9023  if(GiveMessage)
9024  {
9025  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
9026  }
9027  Utilities->CallLogPop(2255);
9028  return(true);
9029  }
9030  }
9031  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
9032  {
9033  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
9034  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
9035  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
9036  {
9038  {
9039  if(GiveMessage)
9040  {
9041  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
9042  }
9043  Utilities->CallLogPop(2256);
9044  return(true);
9045  }
9046  }
9047  }
9048  Utilities->CallLogPop(2257);
9049  return(false); //OK, no duplicates
9050 }
9051 
9052 // ---------------------------------------------------------------------------
9053 
9055 {
9056  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
9057  THVPair HVPair;
9058  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
9059  //for use in the duplicate check
9060  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
9061  {
9062  if(LNMMIt->second < 0) //active track element
9063  {
9064  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
9065  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
9066  }
9067  else //inactive track element
9068  {
9069  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
9070  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
9071  }
9072  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
9073  }
9074  //All HVPairs now present in HVPairsLinkedMap for the specific location name
9075 
9076  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
9077  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
9078  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
9079 
9080  std::list<THVPair> HVLinkedList;
9081 
9082  //set the first value to true and add it to the list
9083  HVPairsLinkedMap.begin()->second = true;
9084  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
9085  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
9086  //examination
9087  THVPair HVPairUnderExamination;
9088  THVPairsLinkedMap::iterator HVPLMIt;
9089  THVPair HVPairNew;
9090  while(!HVLinkedList.empty())
9091  {
9092  HVPairUnderExamination = HVLinkedList.front();
9093  HVLinkedList.pop_front();
9094  HVPairNew.first = HVPairUnderExamination.first;
9095  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
9096  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9097  if(HVPLMIt != HVPairsLinkedMap.end())
9098  {
9099  if(!HVPLMIt->second)
9100  {
9101  HVLinkedList.push_back(HVPLMIt->first);
9102  }
9103  HVPLMIt->second = true;
9104  }
9105  HVPairNew.first = HVPairUnderExamination.first - 1;
9106  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
9107  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9108  if(HVPLMIt != HVPairsLinkedMap.end())
9109  {
9110  if(!HVPLMIt->second)
9111  {
9112  HVLinkedList.push_back(HVPLMIt->first);
9113  }
9114  HVPLMIt->second = true;
9115  }
9116  HVPairNew.first = HVPairUnderExamination.first;
9117  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
9118  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9119  if(HVPLMIt != HVPairsLinkedMap.end())
9120  {
9121  if(!HVPLMIt->second)
9122  {
9123  HVLinkedList.push_back(HVPLMIt->first);
9124  }
9125  HVPLMIt->second = true;
9126  }
9127  HVPairNew.first = HVPairUnderExamination.first + 1;
9128  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
9129  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
9130  if(HVPLMIt != HVPairsLinkedMap.end())
9131  {
9132  if(!HVPLMIt->second)
9133  {
9134  HVLinkedList.push_back(HVPLMIt->first);
9135  }
9136  HVPLMIt->second = true;
9137  }
9138  }
9139 
9140  //at the end if any have a false bool then the name is duplicated so return false
9141  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
9142  {
9143  if(!HVPLMIt->second)
9144  {
9145  Utilities->CallLogPop(2258);
9146  return(false);
9147  }
9148  }
9149  Utilities->CallLogPop(2259);
9150  return(true);
9151 }
9152 
9153 // ---------------------------------------------------------------------------
9154 
9155 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
9156 /*
9157  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
9158 */
9159 
9160 {
9161  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
9162  if(LocationName == "")
9163  {
9164  Utilities->CallLogPop(577);
9165  return(false);
9166  }
9167 // new for v0.2b
9168 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
9170  {
9171  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
9172  ActiveTrackElementNameMap.clear();
9173  for(unsigned int x = 0; x < TrackVector.size(); x++)
9174  {
9175  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
9176  == ContinuationNameMap.end())
9177  {
9178  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
9179  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
9180  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
9181  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
9182  }
9183  }
9185  }
9186  Utilities->CallLogPop(578);
9187  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
9188 // end of new section
9189 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
9190 }
9191 
9192 // ---------------------------------------------------------------------------
9193 
9194 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
9195 /*
9196  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
9197  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
9198  new names in the vectors.
9199 */
9200 {
9201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
9202  bool FoundFlag, ErasedFlag = false;
9203  TLocationNameMultiMapIterator SNIterator;
9204  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9205 
9206  if(SNRange.first != SNRange.second)
9207  {
9208  ErasedFlag = true;
9209  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9210  {
9211  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
9212  TVIt->LocationName = "";
9213  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
9214  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
9215  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
9216  {
9217  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
9218  if(FoundFlag)
9219  {
9220  TrackElementAt(25, Position).LocationName = "";
9221  TrackElementAt(26, Position).ActiveTrackElementName = "";
9222  }
9223  }
9224  }
9225  }
9226  if(ErasedFlag)
9227  {
9229  }
9230  CheckLocationNameMultiMap(3); // test
9231  Utilities->CallLogPop(579);
9232 }
9233 
9234 // ---------------------------------------------------------------------------
9235 
9236 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
9237 /*
9238  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
9239  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
9240  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
9241  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during PlotAndAddTrackElement,
9242  to bring the named location and timetable naming up to date with the deletion or insertion. Note that only one name is sought,
9243  it is entered into LNPendingList and EnterLocationName sets all others.
9244 */
9245 {
9246  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
9247  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
9248  LNPendingList.clear();
9249  AnsiString LocationName;
9250  int MapPos;
9251  bool FoundFlag = 0;
9252 
9253 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9254  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
9255  if(FoundFlag)
9256  {
9257  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
9258  if(LocationName != "")
9259  {
9260  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
9261  EnterLocationName(13, LocationName, true);
9262  Utilities->CallLogPop(2251);
9263  return;
9264  }
9265  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
9266  if(LocationName != "")
9267  {
9268  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
9269  EnterLocationName(14, LocationName, true);
9270  Utilities->CallLogPop(2252);
9271  return;
9272  }
9273  }
9274 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
9275 
9276  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
9277  if(FoundFlag)
9278  {
9279  LocationName = TrackElementAt(1004, Position).LocationName;
9280  if(LocationName != "")
9281  {
9282  int ModifiedPosition = -1 - Position;
9283  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
9284  EnterLocationName(15, LocationName, true);
9285  Utilities->CallLogPop(2253);
9286  return;
9287  }
9288  }
9289  if(SpeedTag == 76) // top plat
9290  {
9291  for(int x = 0; x < 25; x++)
9292  {
9293  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
9294  {
9295  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9296  EnterLocationName(3, LocationName, true);
9297  break;
9298  }
9299  }
9300  }
9301  else if(SpeedTag == 77) // bot plat
9302  {
9303  for(int x = 0; x < 25; x++)
9304  {
9305  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
9306  {
9307  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9308  EnterLocationName(4, LocationName, true);
9309  break;
9310  }
9311  }
9312  }
9313  else if(SpeedTag == 78) // l plat
9314  {
9315  for(int x = 0; x < 25; x++)
9316  {
9317  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
9318  {
9319  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9320  EnterLocationName(5, LocationName, true);
9321  break;
9322  }
9323  }
9324  }
9325  else if(SpeedTag == 79) // r plat
9326  {
9327  for(int x = 0; x < 25; x++)
9328  {
9329  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
9330  {
9331  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9332  EnterLocationName(6, LocationName, true);
9333  break;
9334  }
9335  }
9336  }
9337  else if(SpeedTag == 96) // conc
9338  {
9339  for(int x = 0; x < 28; x++)
9340  {
9341  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
9342  {
9343  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9344  EnterLocationName(7, LocationName, true);
9345  break;
9346  }
9347  }
9348  }
9349  else if(SpeedTag == 129) // vert footbridge
9350  {
9351  for(int x = 0; x < 8; x++)
9352  {
9353  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
9354  {
9355  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9356  EnterLocationName(8, LocationName, true);
9357  break;
9358  }
9359  }
9360  }
9361  else if(SpeedTag == 130) // hor footbridge
9362  {
9363  for(int x = 0; x < 8; x++)
9364  {
9365  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
9366  {
9367  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9368  EnterLocationName(9, LocationName, true);
9369  break;
9370  }
9371  }
9372  }
9373  else if(SpeedTag == 145) // vert u'pass
9374  {
9375  for(int x = 0; x < 8; x++)
9376  {
9377  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
9378  {
9379  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9380  EnterLocationName(11, LocationName, true);
9381  break;
9382  }
9383  }
9384  }
9385  else if(SpeedTag == 146) // hor u'pass
9386  {
9387  for(int x = 0; x < 8; x++)
9388  {
9389  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
9390  {
9391  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9392  EnterLocationName(12, LocationName, true);
9393  break;
9394  }
9395  }
9396  }
9397  else if(SpeedTag == 131) // named location
9398  {
9399  for(int x = 0; x < 4; x++)
9400  {
9401  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
9402  {
9403  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
9404  EnterLocationName(10, LocationName, true);
9405  Utilities->CallLogPop(2657);
9406  return;
9407  }
9408  }
9409  int TVPos = GetVectorPositionFromTrackMap(68, HLoc, VLoc, FoundFlag); //deal with gaps, added at v2.18.0
9410  {
9411  if(FoundFlag && TrackElementAt(1589, TVPos).TrackType == GapJump)
9412  {
9413  int GJTVPos = TrackElementAt(1590, TVPos).Conn[0];
9414  if(GJTVPos > -1)
9415  {
9416  int HLoc2 = TrackElementAt(1591, GJTVPos).HLoc;
9417  int VLoc2 = TrackElementAt(1592, GJTVPos).VLoc;
9418  LocationName = TrackElementAt(1593, GJTVPos).ActiveTrackElementName;
9419  bool FoundFlag2 = false;
9420  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(34, HLoc2, VLoc2, FoundFlag2);
9421  if(FoundFlag2)
9422  {
9423  if(Track->InactiveTrackElementAt(1411, IMPair.first).SpeedTag == 131) //only need first as second is for platforms
9424  {
9425  LNPendingList.insert(LNPendingList.end(), IMPair.first);
9426  EnterLocationName(16, LocationName, true);
9427  }
9428  }
9429  }
9430  }
9431  }
9432  }
9433 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
9434  Utilities->CallLogPop(580);
9435 }
9436 
9437 // ---------------------------------------------------------------------------
9438 
9439 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
9440 /*
9441  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
9442  true if a LocationName is found, and also returns the name and the adjusted vector position.
9443 */
9444 {
9445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
9446  AnsiString(SpeedTag));
9447  bool FoundFlag;
9448  TIMPair IMPair;
9449  TTrackVectorIterator TempElement;
9450  int Position;
9451 
9452  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
9453  if(FoundFlag)
9454  {
9455  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
9456  {
9457  TempElement = InactiveTrackVector.begin() + IMPair.first;
9458  if(TempElement->LocationName != "")
9459  {
9460  LocationName = TempElement->LocationName;
9461  FoundElement = IMPair.first;
9462  Utilities->CallLogPop(581);
9463  return(true);
9464  }
9465  }
9466  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
9467  {
9468  TempElement = InactiveTrackVector.begin() + IMPair.second;
9469  if(TempElement->LocationName != "")
9470  {
9471  LocationName = TempElement->LocationName;
9472  FoundElement = IMPair.second;
9473  Utilities->CallLogPop(582);
9474  return(true);
9475  }
9476  }
9477  }
9478  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
9479  if(FoundFlag)
9480  {
9481  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
9482  {
9483  TempElement = TrackVector.begin() + Position;
9484  if(TempElement->LocationName != "")
9485  {
9486  LocationName = TempElement->LocationName;
9487  FoundElement = -1 - Position;
9488  Utilities->CallLogPop(583);
9489  return(true);
9490  }
9491  }
9492  }
9493  Utilities->CallLogPop(584);
9494  return(false);
9495 }
9496 
9497 // ---------------------------------------------------------------------------
9498 
9499 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
9500 {
9501 // check quantity in map & vectors match
9502  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9503  unsigned int Count = 0;
9504 
9505  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9506  {
9507  Utilities->CallLogPop(2059);
9508  return;
9509  }
9510  AnsiString SName, TName, ErrorString;
9511 
9512  for(unsigned int x = 0; x < TrackVector.size(); x++)
9513  {
9514  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9515  {
9516  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9517  {
9518  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9519  AnsiString(Caller));
9520  }
9521  Count++;
9522  }
9523  }
9524  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9525  {
9526  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9527  {
9528  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9529  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9530  {
9531  throw Exception
9532  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9533  AnsiString(Caller));
9534  }
9535  Count++;
9536  }
9537  }
9538  if(LocationNameMultiMap.size() != Count)
9539  {
9540  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9541  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9542  }
9543 // check all entries in both vectors match entries in name multimap
9545 
9546  for(unsigned int x = 0; x < TrackVector.size(); x++)
9547  {
9548  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9549  {
9550  SName = TrackElementAt(1365, x).LocationName;
9551  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9552  if(ErrorString != "")
9553  {
9554  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9555  }
9556  if(SNIt->second != -1 - (int)x)
9557  {
9558  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9559  AnsiString(Caller));
9560  }
9561  }
9562  // check corresponding platform for all Timetable entries that aren't empty
9563  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9564  TIMPair IMPair;
9565  bool FoundFlag = false;
9566  if(TName != "")
9567  {
9568  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9569  if(FoundFlag)
9570  {
9571  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9573  {
9574  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9575  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9576  }
9577  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9578  {
9579  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9580  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9581  AnsiString(Caller));
9582  }
9583  }
9584  else
9585  {
9586  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9587  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9588  }
9589  }
9590  }
9591  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9592  {
9593  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9594  {
9595  SName = InactiveTrackElementAt(148, x).LocationName;
9596  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9597  if(ErrorString != "")
9598  {
9599  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9600  }
9601  if(SNIt->second != (int)x)
9602  {
9603  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9604  AnsiString(Caller));
9605  }
9606  }
9607  }
9608  Utilities->CallLogPop(585);
9609 }
9610 
9611 // ---------------------------------------------------------------------------
9612 
9614  AnsiString &ErrorString)
9615 {
9616 /*
9617  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9618  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9619  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9620 */
9621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9622  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9623  ErrorString = "";
9624  bool FoundFlag = false;
9625  TLocationNameMultiMapIterator SNIterator;
9626  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9627 
9628  if(SNRange.first == SNRange.second)
9629  {
9630  ErrorString = "Error, Name " + LocationName + " not found in map";
9631  Utilities->CallLogPop(586);
9632  return(SNRange.first);
9633  }
9634  else
9635  {
9636  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9637  {
9638  if(SNIterator->second < 0)
9639  {
9640  int TVPos = -1 - SNIterator->second;
9641  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9642  if(TVIt == TrackElement)
9643  {
9644  FoundFlag = true;
9645  Utilities->CallLogPop(587);
9646  return(SNIterator);
9647  }
9648  }
9649  else
9650  {
9651  int ITVPos = SNIterator->second;
9652  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9653  if(ITVIt == TrackElement)
9654  {
9655  FoundFlag = true;
9656  Utilities->CallLogPop(588);
9657  return(SNIterator);
9658  }
9659  }
9660  }
9661  }
9662  if(!FoundFlag)
9663  {
9664  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9665  }
9666  Utilities->CallLogPop(589);
9667  return(SNIterator);
9668 }
9669 
9670 // ---------------------------------------------------------------------------
9671 
9672 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9673 {
9674 /*
9675  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9676  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9677 */
9678  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9679  TLocationNameMultiMapEntry LocationNameEntry;
9680 
9681  LocationNameEntry.first = NewName;
9682  LocationNameEntry.second = SNIterator->second;
9683  LocationNameMultiMap.erase(SNIterator);
9684  LocationNameMultiMap.insert(LocationNameEntry);
9685  Utilities->CallLogPop(590);
9686 }
9687 
9688 // ---------------------------------------------------------------------------
9689 
9691 {
9692 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9693  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9694  if(Position < 0) // footcrossing
9695  {
9696  int TruePos = -1 - Position;
9697  // new check at v0.2b
9698  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9699  {
9700  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9701  }
9702  Utilities->CallLogPop(591);
9703  return (TrackVector.begin() + TruePos);
9704  }
9705  else
9706  {
9707  // new check at v0.2b
9708  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9709  {
9710  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9711  }
9712  Utilities->CallLogPop(592);
9713  return (InactiveTrackVector.begin() + Position);
9714  }
9715 }
9716 
9717 // ---------------------------------------------------------------------------
9718 
9719 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9720 {
9721 /*
9722  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9723  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9724  LocationNameMultiMap.
9725 */
9726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9727  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9728  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9729 
9730  if(!InactiveTrack2MultiMap.empty())
9731  {
9732  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9733  InactiveTrack2MultiMapIterator++)
9734  {
9735  if(InactiveTrack2MultiMapIterator->second > VecPos)
9736  {
9737  InactiveTrack2MultiMapIterator->second--;
9738  }
9739  // can't be == VecPos as that position erased
9740  }
9741  }
9742  if(!LocationNameMultiMap.empty())
9743  {
9744  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9745  LocationNameMultiMapIterator++)
9746  {
9747  if(LocationNameMultiMapIterator->second < 0)
9748  {
9749  continue; // deal with TrackVectors separately
9750  }
9751  if(LocationNameMultiMapIterator->second > (int)VecPos)
9752  {
9753  LocationNameMultiMapIterator->second--;
9754  }
9755  }
9756  }
9757  Utilities->CallLogPop(593);
9758 }
9759 
9760 // ---------------------------------------------------------------------------
9761 
9762 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9763 {
9764 /*
9765  After an element has been erased from the track vector, all the later elements are moved down one. This function
9766  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9767  LocationNameMultiMap.
9768 */
9769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9770  TTrackMapIterator TrackMapIterator;
9771  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9772 
9773  if(!TrackMap.empty())
9774  {
9775  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9776  {
9777  if(TrackMapIterator->second > VecPos)
9778  {
9779  TrackMapIterator->second--;
9780  }
9781  // can't be == VecPos as that position erased
9782  }
9783  }
9784  if(!LocationNameMultiMap.empty())
9785  {
9786  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9787  LocationNameMultiMapIterator++)
9788  {
9789  if(LocationNameMultiMapIterator->second >= 0)
9790  {
9791  continue; // deal with InactiveTrackVectors separately
9792  }
9793  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9794  // Val -1 -2 -3 -4 -5 -6 -7 -8
9795  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9796  {
9797  LocationNameMultiMapIterator->second++;
9798  }
9799  }
9800  }
9801  for(unsigned int x = 0; x < TrackVector.size(); x++)
9802  {
9803  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9804  if(TkEl.TrackType == GapJump)
9805  {
9806  // position 0 is the gap
9807  if(TkEl.Conn[0] == int(VecPos))
9808  {
9809  TkEl.Conn[0] = -1; // connected to a deleted gap
9810  continue;
9811  }
9812  if(TkEl.Conn[0] > int(VecPos))
9813  {
9814  TkEl.Conn[0]--;
9815  }
9816  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9817  {
9818  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9819  {
9820  TkEl.Conn[0] = -1;
9821  }
9822  }
9823  }
9824  }
9825  Utilities->CallLogPop(1433);
9826 }
9827 
9828 // ---------------------------------------------------------------------------
9829 
9831 /*
9832  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9833  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9834  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9835  InactiveTrackvector values are stored as they are, 0 to n, whereas ActiveTrackvector values stored as -1 - TVPos, i.e.
9836  running from -1 to -1 - n
9837 */
9838 {
9839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9840  LocationNameMultiMap.clear();
9841  TLocationNameMultiMapEntry LocationNameEntry;
9842  TTrackElement TrackElement;
9843 
9844  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9845  {
9846  TrackElement = TrackElementAt(1376, TVPos);
9847  if(TrackElement.FixedNamedLocationElement)
9848  {
9849  LocationNameEntry.first = TrackElement.LocationName;
9850  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9851  LocationNameMultiMap.insert(LocationNameEntry);
9852  }
9853  }
9854 
9855  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9856  {
9857  TrackElement = InactiveTrackElementAt(149, ITVPos);
9858  if(TrackElement.FixedNamedLocationElement)
9859  {
9860  LocationNameEntry.first = TrackElement.LocationName;
9861  LocationNameEntry.second = ITVPos;
9862  LocationNameMultiMap.insert(LocationNameEntry);
9863  }
9864  }
9865  Utilities->CallLogPop(594);
9866 }
9867 
9868 // ---------------------------------------------------------------------------
9869 
9871 // Return true if there is a named location present in the railway
9872 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9873 {
9874  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9875  TTrackVectorIterator ITVI;
9876 
9877  if(InactiveTrackVector.empty())
9878  {
9879  Utilities->CallLogPop(1343);
9880  return(false);
9881  }
9882  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9883  {
9884  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9885  {
9886  Utilities->CallLogPop(1404);
9887  return(true);
9888  }
9889  }
9890  Utilities->CallLogPop(1344);
9891  return(false);
9892 }
9893 
9894 // ---------------------------------------------------------------------------
9895 
9897 /*
9898  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9899 */
9900 {
9901  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9902 // ResetDistanceElements(6);
9903  for(unsigned int x = 0; x < TrackVector.size(); x++)
9904  {
9905  TTrackElement &TE = TrackElementAt(718, x);
9908  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9909  {
9912  }
9913  }
9914 /* old function
9915  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9916  {
9917  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9918  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9919  }
9920  else
9921  {
9922  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9923  }
9924  }
9925 */
9926  Utilities->CallLogPop(617);
9927 }
9928 
9929 // ---------------------------------------------------------------------------
9930 
9932 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLengthandSpeed.
9933 {
9934  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthandSpeedMarker");
9935  for(unsigned int x = 0; x < TrackVector.size(); x++)
9936  {
9937  TTrackElement TempElement = TrackElementAt(1377, x);
9938  if(TempElement.Length01 > -1)
9939  {
9940  MarkOneLengthandSpeed(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9941  }
9942  if(TempElement.Length23 > -1)
9943  {
9944  MarkOneLengthandSpeed(2, TempElement, false, Disp);
9945  }
9946  }
9947  Disp->Update();
9948  Utilities->CallLogPop(618);
9949 }
9950 
9951 // ---------------------------------------------------------------------------
9952 void TTrack::LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp) //Length false -> speed heatmap //unused //added at v2.22.0
9953 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using OneLengthOrSpeedHeatMapColour
9954 {
9955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthOrSpeedHeatMap");
9956  for(unsigned int x = 0; x < TrackVector.size(); x++)
9957  {
9958  TTrackElement TempElement = TrackElementAt(1689, x);
9959  if(((TempElement.HLoc - Display->DisplayOffsetH) >= 0) && ((TempElement.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
9960  ((TempElement.VLoc - Display->DisplayOffsetV) >= 0) && ((TempElement.VLoc - Display->DisplayOffsetV) < Utilities->ScreenElementHeight))
9961  {//only plot if onscreen as takes quite a long time
9962  if(TempElement.Length01 > -1)
9963  {
9964  OneLengthOrSpeedHeatMapColour(8, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9965  }
9966  if(TempElement.Length23 > -1)
9967  {
9968  OneLengthOrSpeedHeatMapColour(9, TempElement, false, Disp);
9969  }
9970  }
9971  }
9972  Disp->Update();
9973  Utilities->CallLogPop(2722);
9974 }
9975 
9976 // ---------------------------------------------------------------------------
9977 
9978 void TTrack::OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp) //added at v2.22.0
9979 
9980 {
9981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneLengthOrSpeedHeatMapColour," + TrackElement.LogTrack(8) + "," +
9982  AnsiString((short)FirstTrack));
9983 
9984  int EXArray[16][2] =
9985  {{4, 6}, {2, 8}, // horizontal & vertical
9986  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9987  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9988  {1, 9}, {3, 7}}; // forward & reverse diagonals
9989 
9990  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink; //BrNum = bridge number, GrNum = graphic number
9991  Graphics::TBitmap *Bitmap;
9992  int Length;
9993  int Speed;
9994 
9995  if(FirstTrack)
9996  {
9997  InLink = TrackElement.Link[0];
9998  OutLink = TrackElement.Link[1];
9999  Length = TrackElement.Length01;
10000  Speed = TrackElement.SpeedLimit01;
10001  }
10002  else
10003  {
10004  InLink = TrackElement.Link[2];
10005  OutLink = TrackElement.Link[3];
10006  Length = TrackElement.Length23;
10007  Speed = TrackElement.SpeedLimit23;
10008  }
10009  for(int x = 0; x < 16; x++)
10010  {
10011  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
10012  {
10013  Index = x;
10014  }
10015  }
10016  if(Index == -1)
10017  {
10018  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
10019  }
10020 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
10021  the graphic for each of which is different because of the shape of the overbridge. The basic
10022  entry/exit value is computed above, and this used to select only from elements with that entry/exit
10023  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
10024  Note that the underbridge track always uses links 2 & 3
10025  int BrEXArray[24][2] = {
10026  {4,6},{2,8},{1,9},{3,7},
10027  {1,9},{3,7},{1,9},{3,7},
10028  {2,8},{4,6},{2,8},{4,6}
10029 */
10030 
10031  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
10032  {
10033  if(Index == 1)
10034  {
10035  if(TrackElement.SpeedTag == 49)
10036  {
10037  BrNum = 1 + 16;
10038  }
10039  else if(TrackElement.SpeedTag == 54)
10040  {
10041  BrNum = 8 + 16;
10042  }
10043  else if(TrackElement.SpeedTag == 55)
10044  {
10045  BrNum = 10 + 16;
10046  }
10047  }
10048  else if(Index == 0)
10049  {
10050  if(TrackElement.SpeedTag == 48)
10051  {
10052  BrNum = 0 + 16;
10053  }
10054  else if(TrackElement.SpeedTag == 58)
10055  {
10056  BrNum = 11 + 16;
10057  }
10058  else if(TrackElement.SpeedTag == 59)
10059  {
10060  BrNum = 9 + 16;
10061  }
10062  }
10063  else if(Index == 14)
10064  {
10065  if(TrackElement.SpeedTag == 50)
10066  {
10067  BrNum = 2 + 16;
10068  }
10069  else if(TrackElement.SpeedTag == 52)
10070  {
10071  BrNum = 4 + 16;
10072  }
10073  else if(TrackElement.SpeedTag == 57)
10074  {
10075  BrNum = 6 + 16;
10076  }
10077  }
10078  else if(Index == 15)
10079  {
10080  if(TrackElement.SpeedTag == 51)
10081  {
10082  BrNum = 3 + 16;
10083  }
10084  else if(TrackElement.SpeedTag == 53)
10085  {
10086  BrNum = 7 + 16;
10087  }
10088  else if(TrackElement.SpeedTag == 56)
10089  {
10090  BrNum = 5 + 16;
10091  }
10092  }
10093  }
10094  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10095  {
10096  GrNum = BrNum;
10097  }
10098  else
10099  {
10100  GrNum = Index;
10101  }
10102 
10103 //get basic track bitmap
10104  if(GrNum > 15) // underbridge
10105  {
10106  Bitmap = RailGraphics->BridgeGraphicsPtr[GrNum - 16];
10107  }
10108  else
10109  {
10110  Bitmap = RailGraphics->LinkGraphicsPtr[GrNum];
10111  }
10112  if(TrackElement.SpeedTag == 64)
10113  {
10114  Bitmap = RailGraphics->LinkGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10115  }
10116  if(TrackElement.SpeedTag == 65)
10117  {
10118  Bitmap = RailGraphics->LinkGraphicsPtr[17];
10119  }
10120  if(TrackElement.SpeedTag == 66)
10121  {
10122  Bitmap = RailGraphics->LinkGraphicsPtr[18];
10123  }
10124  if(TrackElement.SpeedTag == 67)
10125  {
10126  Bitmap = RailGraphics->LinkGraphicsPtr[19];
10127  }
10128  if(TrackElement.SpeedTag == 80)
10129  {
10130  Bitmap = RailGraphics->LinkGraphicsPtr[20]; // intercept continuations to show the dots
10131  }
10132  if(TrackElement.SpeedTag == 81)
10133  {
10134  Bitmap = RailGraphics->LinkGraphicsPtr[21];
10135  }
10136  if(TrackElement.SpeedTag == 82)
10137  {
10138  Bitmap = RailGraphics->LinkGraphicsPtr[22];
10139  }
10140  if(TrackElement.SpeedTag == 83)
10141  {
10142  Bitmap = RailGraphics->LinkGraphicsPtr[23];
10143  }
10144  if(TrackElement.SpeedTag == 84)
10145  {
10146  Bitmap = RailGraphics->LinkGraphicsPtr[24];
10147  }
10148  if(TrackElement.SpeedTag == 85)
10149  {
10150  Bitmap = RailGraphics->LinkGraphicsPtr[25];
10151  }
10152  if(TrackElement.SpeedTag == 86)
10153  {
10154  Bitmap = RailGraphics->LinkGraphicsPtr[26];
10155  }
10156  if(TrackElement.SpeedTag == 87)
10157  {
10158  Bitmap = RailGraphics->LinkGraphicsPtr[27];
10159  }
10160  if(TrackElement.SpeedTag == 129)
10161  {
10162  Bitmap = RailGraphics->LinkGraphicsPtr[28]; // intercept under footbridges
10163  }
10164  if(TrackElement.SpeedTag == 130)
10165  {
10166  Bitmap = RailGraphics->LinkGraphicsPtr[29];
10167  }
10168 
10169 // RailGraphics->HeatMapGraphic->Assign(Bitmap); //make a copy prior to colouring <- no good, copies bits per pixel too
10170  TRect Rect(0,0,16,16);
10171  RailGraphics->HeatMapGraphic->Canvas->CopyRect(Rect, Bitmap->Canvas, Rect); //this is better, high colour resolution retained
10172  RailGraphics->HeatMapGraphic->TransparentColor = Utilities->clTransparent;
10173  //determine color required
10174  int Red, Green, Blue; //int values will be between 0 & 255
10175  int *R = &Red, *G = &Green, *B = &Blue;
10176  TColor Col;
10177  float Len, Spd;
10178  if(LengthHeatMapFlag)
10179  {
10180  if(Utilities->RedLowFlag)
10181  {
10182  Len = Length/10;
10183  }
10184  else
10185  {
10186  Len = 3000/Length;
10187  }
10188  RailGraphics->GetHeatMapColor(0, (Ln(Len))/5.704, R, G, B); //Len/10 makes range 1 to limit of 300, representing 3000km per element {3000/Len] for reverse spectrum
10189  Col = TColor((65536 * Blue) + (256 * Green) + Red); //5.704 normalises Ln range to between 0 & 1
10191  } //use ChangeForegroundColour2 as faster
10192  else if (SpeedHeatMapFlag)
10193  {
10194  if(Utilities->RedLowFlag)
10195  {
10196  Spd = Speed/10;
10197  }
10198  else
10199  {
10200  Spd = 400/Speed;
10201  }
10202  RailGraphics->GetHeatMapColor(1, (Ln(Spd))/3.691, R, G, B); //Spd/10 makes range 1 to limit of 40, representing 400km/h [400/Spd] for reverse spectrum
10203  Col = TColor((65536 * Blue) + (256 * Green) + Red); //3.691 normalises Ln range to between 0 & 1
10205  } //use ChangeForegroundColour2 as faster
10206  else
10207  {
10208  Utilities->CallLogPop(2721);
10209  return;
10210  }
10211  Disp->PlotOutput(289, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->HeatMapGraphic);
10212  Utilities->CallLogPop(2723);
10213 }
10214 
10215 // ---------------------------------------------------------------------------
10216 
10217 void TTrack::MarkOneLengthandSpeed(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
10218 /*
10219  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h normally but can be changed in Config.txt
10220  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
10221  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
10222  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
10223  track as indicated by FirstTrack (true for track01 & false for track23).
10224 */
10225 {
10226  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLengthandSpeed," + TrackElement.LogTrack(8) + "," +
10227  AnsiString((short)FirstTrack));
10228  bool LengthDifferent = false, SpeedDifferent = false; //BrNum = bridge number, GrNum = graphic number
10229 
10230  if(IsElementDefaultLengthAndSpeed(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
10231  {
10232  Utilities->CallLogPop(619);
10233  return;
10234  }
10235  int EXArray[16][2] =
10236  {{4, 6}, {2, 8}, // horizontal & vertical
10237  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
10238  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
10239  {1, 9}, {3, 7}}; // forward & reverse diagonals
10240 
10241  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
10242  Graphics::TBitmap *Bitmap;
10243 
10244  if(FirstTrack)
10245  {
10246  InLink = TrackElement.Link[0];
10247  OutLink = TrackElement.Link[1];
10248  }
10249  else
10250  {
10251  InLink = TrackElement.Link[2];
10252  OutLink = TrackElement.Link[3];
10253  }
10254  for(int x = 0; x < 16; x++)
10255  {
10256  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
10257  {
10258  Index = x;
10259  }
10260  }
10261  if(Index == -1)
10262  {
10263  throw Exception("Error, failed to find Index in TTrack::MarkOneLengthandSpeed");
10264  }
10265 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
10266  the graphic for each of which is different because of the shape of the overbridge. The basic
10267  entry/exit value is computed above, and this used to select only from elements with that entry/exit
10268  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
10269  Note that the underbridge track always uses links 2 & 3
10270  int BrEXArray[24][2] = {
10271  {4,6},{2,8},{1,9},{3,7},
10272  {1,9},{3,7},{1,9},{3,7},
10273  {2,8},{4,6},{2,8},{4,6}
10274 */
10275  if(!FirstTrack && (TrackElement.TrackType == Bridge)) //underbridge track always uses links 2 & 3 so never FirstTrack
10276  {
10277  if(Index == 1)
10278  {
10279  if(TrackElement.SpeedTag == 49)
10280  {
10281  BrNum = 1 + 16;
10282  }
10283  else if(TrackElement.SpeedTag == 54)
10284  {
10285  BrNum = 8 + 16;
10286  }
10287  else if(TrackElement.SpeedTag == 55)
10288  {
10289  BrNum = 10 + 16;
10290  }
10291  }
10292  else if(Index == 0)
10293  {
10294  if(TrackElement.SpeedTag == 48)
10295  {
10296  BrNum = 0 + 16;
10297  }
10298  else if(TrackElement.SpeedTag == 58)
10299  {
10300  BrNum = 11 + 16;
10301  }
10302  else if(TrackElement.SpeedTag == 59)
10303  {
10304  BrNum = 9 + 16;
10305  }
10306  }
10307  else if(Index == 14)
10308  {
10309  if(TrackElement.SpeedTag == 50)
10310  {
10311  BrNum = 2 + 16;
10312  }
10313  else if(TrackElement.SpeedTag == 52)
10314  {
10315  BrNum = 4 + 16;
10316  }
10317  else if(TrackElement.SpeedTag == 57)
10318  {
10319  BrNum = 6 + 16;
10320  }
10321  }
10322  else if(Index == 15)
10323  {
10324  if(TrackElement.SpeedTag == 51)
10325  {
10326  BrNum = 3 + 16;
10327  }
10328  else if(TrackElement.SpeedTag == 53)
10329  {
10330  BrNum = 7 + 16;
10331  }
10332  else if(TrackElement.SpeedTag == 56)
10333  {
10334  BrNum = 5 + 16;
10335  }
10336  }
10337  }
10338  if(!FirstTrack && (TrackElement.TrackType == Bridge))
10339  {
10340  GrNum = BrNum;
10341  }
10342  else
10343  {
10344  GrNum = Index;
10345  }
10346  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
10347  {
10348  if(GrNum > 15) // underbridge
10349  {
10350  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
10351  }
10352  else
10353  {
10354  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
10355  }
10356  if(TrackElement.SpeedTag == 64)
10357  {
10358  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10359  }
10360  if(TrackElement.SpeedTag == 65)
10361  {
10363  }
10364  if(TrackElement.SpeedTag == 66)
10365  {
10367  }
10368  if(TrackElement.SpeedTag == 67)
10369  {
10371  }
10372  if(TrackElement.SpeedTag == 80)
10373  {
10374  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
10375  }
10376  if(TrackElement.SpeedTag == 81)
10377  {
10379  }
10380  if(TrackElement.SpeedTag == 82)
10381  {
10383  }
10384  if(TrackElement.SpeedTag == 83)
10385  {
10387  }
10388  if(TrackElement.SpeedTag == 84)
10389  {
10391  }
10392  if(TrackElement.SpeedTag == 85)
10393  {
10395  }
10396  if(TrackElement.SpeedTag == 86)
10397  {
10399  }
10400  if(TrackElement.SpeedTag == 87)
10401  {
10403  }
10404  if(TrackElement.SpeedTag == 129)
10405  {
10406  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
10407  }
10408  if(TrackElement.SpeedTag == 130)
10409  {
10411  }
10412  }
10413 
10414  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
10415  {
10416  if(GrNum > 15) // underbridge
10417  {
10418  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
10419  }
10420  else
10421  {
10422  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
10423  }
10424  if(TrackElement.SpeedTag == 64)
10425  {
10426  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10427  }
10428  if(TrackElement.SpeedTag == 65)
10429  {
10430  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
10431  }
10432  if(TrackElement.SpeedTag == 66)
10433  {
10434  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
10435  }
10436  if(TrackElement.SpeedTag == 67)
10437  {
10438  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
10439  }
10440  if(TrackElement.SpeedTag == 80)
10441  {
10442  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10443  }
10444  if(TrackElement.SpeedTag == 81)
10445  {
10446  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
10447  }
10448  if(TrackElement.SpeedTag == 82)
10449  {
10450  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
10451  }
10452  if(TrackElement.SpeedTag == 83)
10453  {
10454  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
10455  }
10456  if(TrackElement.SpeedTag == 84)
10457  {
10458  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
10459  }
10460  if(TrackElement.SpeedTag == 85)
10461  {
10462  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
10463  }
10464  if(TrackElement.SpeedTag == 86)
10465  {
10466  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
10467  }
10468  if(TrackElement.SpeedTag == 87)
10469  {
10470  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
10471  }
10472  if(TrackElement.SpeedTag == 129)
10473  {
10474  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
10475  }
10476  if(TrackElement.SpeedTag == 130)
10477  {
10478  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
10479  }
10480  }
10481 
10482  else // SpeedDifferent only: red - use non sig graphics
10483  {
10484  if(GrNum > 15) // underbridge
10485  {
10486  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
10487  }
10488  else
10489  {
10490  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
10491  }
10492  if(TrackElement.SpeedTag == 64)
10493  {
10494  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
10495  }
10496  if(TrackElement.SpeedTag == 65)
10497  {
10499  }
10500  if(TrackElement.SpeedTag == 66)
10501  {
10503  }
10504  if(TrackElement.SpeedTag == 67)
10505  {
10507  }
10508  if(TrackElement.SpeedTag == 80)
10509  {
10510  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
10511  }
10512  if(TrackElement.SpeedTag == 81)
10513  {
10515  }
10516  if(TrackElement.SpeedTag == 82)
10517  {
10519  }
10520  if(TrackElement.SpeedTag == 83)
10521  {
10523  }
10524  if(TrackElement.SpeedTag == 84)
10525  {
10527  }
10528  if(TrackElement.SpeedTag == 85)
10529  {
10531  }
10532  if(TrackElement.SpeedTag == 86)
10533  {
10535  }
10536  if(TrackElement.SpeedTag == 87)
10537  {
10539  }
10540  if(TrackElement.SpeedTag == 129)
10541  {
10542  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
10543  }
10544  if(TrackElement.SpeedTag == 130)
10545  {
10547  }
10548  }
10549  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
10550  Utilities->CallLogPop(620);
10551 }
10552 
10553 // ---------------------------------------------------------------------------
10554 
10555 bool TTrack::IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
10556 /* FirstTrack = LinkPos's 0 & 1
10557  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
10558 */
10559 {
10560  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementDefaultLengthAndSpeed," + TrackElement.LogTrack(10) + "," +
10561  AnsiString((short)FirstTrack));
10562  LengthDifferent = false;
10563  SpeedDifferent = false;
10564  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
10565  {
10566  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10567  {
10568  LengthDifferent = true;
10569  }
10570  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10571  {
10572  SpeedDifferent = true;
10573  }
10574  if(LengthDifferent || SpeedDifferent)
10575  {
10576  Utilities->CallLogPop(625);
10577  return(false);
10578  }
10579  Utilities->CallLogPop(626);
10580  return(true);
10581  }
10582 
10583  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
10584  {
10585  if(TrackElement.Length23 != Utilities->DefaultTrackLength)
10586  {
10587  LengthDifferent = true;
10588  }
10589  if(TrackElement.SpeedLimit23 != Utilities->DefaultTrackSpeedLimit)
10590  {
10591  SpeedDifferent = true;
10592  }
10593  if(LengthDifferent || SpeedDifferent)
10594  {
10595  Utilities->CallLogPop(627);
10596  return(false);
10597  }
10598  Utilities->CallLogPop(628);
10599  return(true);
10600  }
10601 
10602  else // any other 1 track element, including platforms being present
10603  {
10604  if(TrackElement.Length01 != Utilities->DefaultTrackLength)
10605  {
10606  LengthDifferent = true;
10607  }
10608  if(TrackElement.SpeedLimit01 != Utilities->DefaultTrackSpeedLimit)
10609  {
10610  SpeedDifferent = true;
10611  }
10612  if(LengthDifferent || SpeedDifferent)
10613  {
10614  Utilities->CallLogPop(629);
10615  return(false);
10616  }
10617  Utilities->CallLogPop(630);
10618  return(true);
10619  }
10620 }
10621 
10622 // ---------------------------------------------------------------------------
10623 
10624 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10625 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
10626 {
10627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10628  AnsiString(VLoc));
10629  bool FoundFlag;
10630  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
10631 
10632  if(!FoundFlag)
10633  {
10634  Utilities->CallLogPop(633);
10635  return(false);
10636  }
10637  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
10638  {
10639  Utilities->CallLogPop(634);
10640  return(true); // only need to check first since if second is a platform the the first must be too
10641  }
10642  else
10643  {
10644  Utilities->CallLogPop(635);
10645  return(false);
10646  }
10647 }
10648 
10649 // ---------------------------------------------------------------------------
10650 
10651 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
10652 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
10653 {
10654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
10655  AnsiString(VLoc));
10656  bool FoundFlag;
10657  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
10658 
10659  if(!FoundFlag)
10660  {
10661  Utilities->CallLogPop(636);
10662  return(false);
10663  }
10665  {
10666  Utilities->CallLogPop(637);
10667  return(true); // only need to check first since only one used for NamedNonStationLocations
10668  }
10669  else
10670  {
10671  Utilities->CallLogPop(638);
10672  return(false);
10673  }
10674 }
10675 
10676 // ---------------------------------------------------------------------------
10677 
10678 void TTrack::SetStationEntryStopLinkPosses(int Caller) //only for platforms
10679 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
10680  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
10681  the front of train stop points for each direction.
10682  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
10683  end (unless buffers at one or both ends in which case stop points are the end elements).
10684  Note that for a single element the stop point is the element itself (formula doesn't apply).
10685  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
10686  repeating the procedure for every element. At the end all unused values are returned to -1.
10687  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
10688 */
10689 {
10690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
10691  TTrackElement TempElement, StartElement;
10692  AnsiString TempName;
10693  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
10694  bool ForwardSet, ReverseSet;
10695 
10696  for(unsigned int x = 0; x < TrackVector.size(); x++)
10697  {
10698  TrackElementAt(1378, x).StationEntryStopLinkPos1 = -1; //this only sets 0 & 1 as all single track elements for platforms
10700  }
10701  for(unsigned int x = 0; x < TrackVector.size(); x++)
10702  {
10703  TempElement = TrackElementAt(1380, x);
10704  if(!IsNamedNonStationLocationPresent(2, TempElement.HLoc, TempElement.VLoc)) //deal with non-station names later
10705  {
10706  ForwardSet = false;
10707  ReverseSet = false;
10708  VecPos = x;
10709  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1) && (TempElement.StationEntryStopLinkPos2 == -1))
10710  // 2nd condition incl so don't re-examine elements with stop links set to 5
10711  {
10712  TempName = TempElement.ActiveTrackElementName;
10713  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10714  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10715  // an element linked at both ends where both links are also named elements
10716  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
10717  {
10718  continue; // looking for an end element so skip this one
10719  }
10720  else // reached one end
10721  {
10722  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
10723  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10724  // single named element linked at both ends, can't be continuation as platforms not allowed there
10725  {
10726  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
10727  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
10728  continue;
10729  }
10730  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10731  // single named buffer element (LinkPos 1 is the non-buffer end)
10732  {
10733  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
10734  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
10735  continue;
10736  }
10737  else
10738  // Note: only interested in connection positions 0 & 1 since all platform elements are single track except points,
10739  // and platforms always on straight (conns 0 & 1) section of points
10740  {
10741  for(int y = 0; y < 2; y++)
10742  {
10743  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
10744  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
10745  /* TTrackElement Temp1 = TempElement;
10746  ***********New section, compiles but not checked - does bit below need to be else if?
10747  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
10748  {
10749  //search along Dir direction until find other end, skip if Dir facing buffer end
10750  int NewDir = Dir;
10751  int NewVecPos;
10752  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
10753  {
10754  NewVecPos = Temp1.Conn[NewDir];
10755  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
10756  Temp1 = TrackElementAt(601, NewVecPos);
10757  }
10758  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
10759  {
10760  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
10761  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
10762  }
10763  }
10764  ***************
10765  */
10766  // end may be linked at both ends but only one link named, or buffer with linked element named
10767  // if a buffer then the named linkpos has to be 1
10768  // already dealt with all types of single element so at least 2 linked named elements
10769  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
10770  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10771  { //element linked at both ends with entry end not same name, or buffers with exit link == 1 (exit link always 1 but need to ensure Dir set correctly)
10772  StartElement = TempElement;
10773  StartVecPos = VecPos; //this stays fixed at start of platform group
10774  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10775  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10776  EntryPos = 1 - Dir;
10777  StartEntryPos = 1 - Dir;
10778  Count = 1;
10779  // work along named elements until find the other end
10780  while((TempElement.Conn[1 - EntryPos] > -1) && (TempElement.Conn[1 - EntryPos] < (int)TrackVector.size()) && (TrackElementAt(53, TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10781  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10782  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10783  // all stop link pos's are set to 5
10784  {
10785  VecPos = TempElement.Conn[1 - EntryPos];
10786  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10787  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10788  EntryPos = TempEntryPos;
10789  Count++;
10790  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10791  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10792  }
10793  // here when reached other end, maybe buffers, or last named linked element
10794  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10795  // terminal station, set end elements as stop elements
10796  {
10797  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10798  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10799  continue;
10800  }
10801  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10802  // terminal station, set end elements as stop elements
10803  {
10804  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10805  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10806  continue;
10807  }
10808  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10809  ForwardNumber = ((Count + 1) / 2) + 1;
10810  ReverseNumber = (Count - ForwardNumber) + 1;
10811  Count = 1; // starting value
10812  EntryPos = 1 - Dir;
10813  TempElement = StartElement;
10814  VecPos = StartVecPos;
10815  if(Count == ForwardNumber)
10816  {
10817  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10818  ForwardSet = true;
10819  }
10820  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10821  {
10822  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10823  ReverseSet = true;
10824  }
10825  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10826  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10827  {
10828  VecPos = TempElement.Conn[1 - EntryPos];
10829  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10830  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10831  EntryPos = TempEntryPos;
10832  Count++;
10833  if(Count == ForwardNumber)
10834  {
10835  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10836  ForwardSet = true;
10837  }
10838  if(Count == ReverseNumber)
10839  {
10840  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10841  ReverseSet = true;
10842  }
10843  }
10844  }
10845  }
10846  }
10847  }
10848  }
10849  }
10850  }
10851  for(unsigned int x = 0; x < TrackVector.size(); x++)
10852  {
10853  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10854  {
10856  }
10857  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10858  {
10860  }
10861  }
10862  Utilities->CallLogPop(639);
10863 }
10864 
10865 // ---------------------------------------------------------------------------
10866 
10867 void TTrack::SetNonStationStopLinkEntryPosses(int Caller) //added at v2.18.0
10868 
10869 {
10870 /*at v2.18.0 allow for 2 tracks on a non-station element. Have StationEntryStopLinkPos1 & 2 contain both track entry positions, 0 & 1 in
10871 least sig 2 bits and 2 & 3 in next least sig bits. In use have SESLPos1a == 0 or 1 and SESLPos1b == 2 or 3, and same for Pos2. 'b' values all
10872 set to 0 for platforms, and set appropriately for 2-track non-station locs. SESLPos values are TTrackElement variables only used in program, not
10873 saved in sessions or railways (same as StationEntryStopLinkPos1 & 2).
10874 
10875 Examine each non-station area with same name and, similar to above, look for cases where a track doesn't link to an element with the same name, or
10876 doesn't link at all, this is an end element, check both tracks separately for 4-track elements.
10877 */
10878  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetNonStationStopLinkEntryPosses");
10879  TTrackElement TempElement;
10880  AnsiString TempName;
10881  std::list<unsigned int> NameList; //end elements
10882  std::list<AnsiString> ContinuationNameList; // list of continuation names so can exclude them
10883  for(unsigned int x = 0; x < TrackVector.size(); x++)
10884  {
10885  TrackElementAt(1594, x).StationEntryStopLinkPos3 = -1; // don't clear stopping points 0 & 1 as already set for platforms
10887  if((TrackElementAt(1596, x).TrackType == Continuation) && (TrackElementAt(1641, x).ActiveTrackElementName != ""))
10888  {
10889  ContinuationNameList.push_back(TrackElementAt(1597, x).ActiveTrackElementName);
10890  }
10891  }
10892  ContinuationNameList.sort();
10893  ContinuationNameList.unique();
10894 
10895  for(unsigned int x = 0; x < TrackVector.size(); x++)
10896  {
10897  TempElement = TrackElementAt(1598, x);
10898  if(IsNamedNonStationLocationPresent(3, TempElement.HLoc, TempElement.VLoc))
10899  {
10900  bool NameIsAContinuation = false;
10901  if(std::find(ContinuationNameList.begin(), ContinuationNameList.end(), TempElement.ActiveTrackElementName) != ContinuationNameList.end())
10902  {
10903  NameIsAContinuation = true;
10904  }
10905  if((TempElement.ActiveTrackElementName != "") && !NameIsAContinuation && (TempElement.StationEntryStopLinkPos1 == -1) &&
10906  (TempElement.StationEntryStopLinkPos2 == -1) && (TempElement.StationEntryStopLinkPos3 == -1) && (TempElement.StationEntryStopLinkPos4 == -1))
10907  // Non-station named elements can't be placed on platforms so no conflict with existing stop positions
10908  {
10909  TempName = TempElement.ActiveTrackElementName;
10910  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(1599, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
10911  (TrackElementAt(1600, TempElement.Conn[1]).ActiveTrackElementName == TempName))
10912  // an element linked at both ends of single or main track where both links are also named elements with same name
10913  {
10914  if(TempElement.TrackType == Points) //for points links 0 and 2 are the same
10915  {
10916  if(((TempElement.Conn[2] > -1)) && (TempElement.Conn[3] > -1) &&
10917  ((TrackElementAt(1601, TempElement.Conn[2]).ActiveTrackElementName == TempName)) &&
10918  (TrackElementAt(1602, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10919  {
10920  continue; //not an end element so skip it
10921  }
10922  else //reached an end on the diverging leg
10923  {
10924  NameList.push_back(x);
10925  }
10926  }
10927  else if(TempElement.TrackType == Crossover)
10928  {
10929  if((TempElement.Conn[2] > -1) && (TempElement.Conn[3] > -1) &&
10930  (TrackElementAt(1603, TempElement.Conn[2]).ActiveTrackElementName == TempName) &&
10931  (TrackElementAt(1604, TempElement.Conn[3]).ActiveTrackElementName == TempName))
10932  {
10933  continue; //not an end element so skip it
10934  }
10935  else
10936  {
10937  NameList.push_back(x);
10938  }
10939  }
10940  else
10941  {
10942  continue; //not points ot crossover & not an end element so skip
10943  }
10944  }
10945  else // reached one end of single or main track
10946  {
10947  NameList.push_back(x);
10948  }
10949 //NameList now contains all non-station end elements
10950  while(!NameList.empty())
10951  {
10952  unsigned int a = NameList.front();
10953  NameList.pop_front();
10954  TTrackElement &TempElement = TrackElementAt(1605, a);
10955  AnsiString TempName = TempElement.ActiveTrackElementName;
10956  if(TempElement.TrackType == Buffers) //buffer end is 0 so entry must be 1, gaps covered below as any other element
10957  {
10958  TempElement.StationEntryStopLinkPos1 = 1;
10959  }
10960  else
10961  {
10962  if((TempElement.Conn[0] == -1) || (TrackElementAt(1606, TempElement.Conn[0]).ActiveTrackElementName != TempName))
10963  {
10964  TempElement.StationEntryStopLinkPos1 = 1;
10965  }
10966  if((TempElement.Conn[1] == -1) || (TrackElementAt(1607, TempElement.Conn[1]).ActiveTrackElementName != TempName))
10967  {
10968  TempElement.StationEntryStopLinkPos2 = 0;
10969  }
10970  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover))
10971  {
10972  if((TempElement.Conn[2] == -1) || (TrackElementAt(1608, TempElement.Conn[2]).ActiveTrackElementName != TempName))
10973  {
10974  TempElement.StationEntryStopLinkPos3 = 3;
10975  }
10976  if((TempElement.Conn[3] == -1) || (TrackElementAt(1609, TempElement.Conn[3]).ActiveTrackElementName != TempName))
10977  {
10978  TempElement.StationEntryStopLinkPos4 = 2;
10979  }
10980  }
10981  }
10982  }
10983  }
10984  }
10985  }
10986  Utilities->CallLogPop(2640);
10987 }
10988 
10989 // ---------------------------------------------------------------------------
10990 
10991 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10992 {
10993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10994  TTrackElement Next;
10995 
10997  while(ReturnNextInactiveTrackElement(1, Next))
10998  {
10999  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
11000  {
11001  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
11002  // need striped graphics
11003  {
11004  if(Next.SpeedTag == 76)
11005  {
11006  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
11007  }
11008  else if(Next.SpeedTag == 77)
11009  {
11010  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
11011  }
11012  else if(Next.SpeedTag == 78)
11013  {
11014  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
11015  }
11016  else if(Next.SpeedTag == 79)
11017  {
11018  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
11019  }
11020  else if(Next.SpeedTag == 96)
11021  {
11022  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
11023  }
11024  else if(Next.SpeedTag == 131)
11025  {
11026  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
11027  }
11028  }
11029  else
11030  {
11031  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
11032  }
11033  }
11034  }
11035 
11036  NextTrackElementPtr = TrackVector.begin();
11037  while(ReturnNextTrackElement(1, Next))
11038  {
11039  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
11040  {
11041  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
11042  {
11043  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
11044  {
11045  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
11046  }
11047  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
11048  {
11049  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
11050  }
11051  }
11052  else
11053  {
11054  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
11055  }
11056  }
11057  }
11058  Disp->Update();
11059  Utilities->CallLogPop(640);
11060 }
11061 
11062 // ---------------------------------------------------------------------------
11063 
11064 void TTrack::PlotSmallRedGap(int Caller)
11065 {
11066  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
11068  Utilities->CallLogPop(1346);
11069 }
11070 
11071 // ---------------------------------------------------------------------------
11072 
11073 void TTrack::TrackClear(int Caller)
11074 {
11075  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
11076  TrackVector.clear();
11077  InactiveTrackVector.clear();
11078  TrackMap.clear();
11080  if(TextHandler->TextVector.size() == 0)
11081  {
11082  Display->DisplayOffsetH = 0;
11083  Display->DisplayOffsetV = 0;
11090  HLocMin = 2000000000;
11091  HLocMax = -2000000000;
11092  VLocMin = 2000000000;
11093  VLocMax = -2000000000;
11094  }
11095  else
11096  {
11097  CalcHLocMinEtc(4);
11098  }
11099  Utilities->CallLogPop(1347);
11100 }
11101 
11102 // ---------------------------------------------------------------------------
11103 
11104 void TTrack::CalcHLocMinEtc(int Caller)
11105 {
11106  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
11107  HLocMin = 2000000000;
11108  VLocMin = 2000000000;
11109  HLocMax = -2000000000;
11110  VLocMax = -2000000000;
11111  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
11112  {
11113  if(TrackElementAt(1385, x).SpeedTag == 0)
11114  {
11115  continue; // skip erase elements or would interfere with Min & Max values
11116  }
11117  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
11118  {
11119  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
11120  }
11121  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
11122  {
11123  HLocMax = TrackElementAt(1389, x).HLoc + 1;
11124  }
11125  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
11126  {
11127  VLocMin = TrackElementAt(1391, x).VLoc - 1;
11128  }
11129  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
11130  {
11131  VLocMax = TrackElementAt(1393, x).VLoc + 1;
11132  }
11133  }
11134  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
11135  {
11136  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
11137  {
11138  continue; // shouldn't be any inactive erase elements but include anyway
11139  }
11140  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
11141  {
11142  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
11143  }
11144  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
11145  {
11146  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
11147  }
11148  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
11149  {
11150  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
11151  }
11152  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
11153  {
11154  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
11155  }
11156  }
11157  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
11158  {
11159 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
11160  will fail as x will exceed the maximum value
11161  if(TextHandler->TextPtrAt(, x)->TextString == "")
11162  {
11163  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
11164  }
11165 */
11166  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
11167  if((TextH / 16) - 1 < HLocMin)
11168  {
11169  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
11170  }
11171  if((TextH / 16) + 1 > HLocMax)
11172  {
11173  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
11174  }
11175  if((TextV / 16) - 1 < VLocMin)
11176  {
11177  VLocMin = (TextV / 16) - 1;
11178  }
11179  if((TextV / 16) + 1 > VLocMax)
11180  {
11181  VLocMax = (TextV / 16) + 1;
11182  }
11183  }
11184  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
11185  {
11186  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
11187  {
11188  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
11189  }
11190  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
11191  {
11192  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
11193  }
11194  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
11195  {
11196  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
11197  }
11198  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
11199  {
11200  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
11201  }
11202  }
11203 
11204  Utilities->CallLogPop(641);
11205 }
11206 
11207 // ---------------------------------------------------------------------------
11208 
11209 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
11210  bool &UserGraphicFoundFlag)
11211 {
11212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
11213  TUserGraphicVector::iterator UserGraphicPtr;
11214 
11215  UserGraphicFoundFlag = false;
11216  if(!UserGraphicVector.empty())
11217  {
11218  int x = UserGraphicVector.size();
11219  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
11220  {
11221  x--;
11222  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
11223  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
11224  {
11225  UserGraphicItem = x;
11226  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
11227  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
11228  UserGraphicFoundFlag = true;
11229  Utilities->CallLogPop(2177);
11230  return;
11231  } // if ....
11232 
11233  } // for UserGraphicPtr...
11234  } // if !UserGraphicVector...
11235 
11236  Utilities->CallLogPop(2197);
11237 }
11238 
11239 // ---------------------------------------------------------------------------
11240 
11242 {
11243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
11244  TrackElement.LogTrack(11));
11245  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
11246  int SpeedTag = TrackElement.SpeedTag;
11247 
11248  if(SpeedTag < 1)
11249  {
11250  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
11251  }
11252  switch(SpeedTag)
11253  {
11254  case 76: // t platform
11255  GraphicOutput = RailGraphics->gl76Striped;
11256  break;
11257 
11258  case 77: // h platform
11259  GraphicOutput = RailGraphics->bm77Striped;
11260  break;
11261 
11262  case 78: // v platform
11263  GraphicOutput = RailGraphics->bm78Striped;
11264  break;
11265 
11266  case 79: // r platform
11267  GraphicOutput = RailGraphics->gl79Striped;
11268  break;
11269 
11270  case 96: // concourse
11271  GraphicOutput = RailGraphics->ConcourseStriped;
11272  break;
11273 
11274  case 129: // v footbridge
11275  GraphicOutput = RailGraphics->gl129Striped;
11276  break;
11277 
11278  case 130: // h footbridge
11279  GraphicOutput = RailGraphics->gl130Striped;
11280  break;
11281 
11282  case 131: // non-station named loc
11283  GraphicOutput = RailGraphics->bmNameStriped;
11284  break;
11285 
11286  case 145: // v u'pass
11287  GraphicOutput = RailGraphics->gl145Striped;
11288  break;
11289 
11290  case 146: // h u'pass
11291  GraphicOutput = RailGraphics->gl146Striped;
11292  break;
11293 
11294  default:
11295  GraphicOutput = TrackElement.GraphicPtr;
11296  break;
11297  }
11298  Utilities->CallLogPop(642);
11299  return(GraphicOutput);
11300 }
11301 
11302 // ---------------------------------------------------------------------------
11303 
11305 {
11306  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
11307  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11308  {
11309 // Utilities->CallLogPop(2281); this shouldn't be here, introduced 02/06/21 at revision 3745fadb... with no explanation
11310  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
11311  }
11312  Utilities->CallLogPop(643);
11313  return(TrackVector.at(At));
11314 }
11315 
11316 // ---------------------------------------------------------------------------
11317 
11319 {
11320  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
11321  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
11322  {
11323  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
11324  " in InactiveTrackElementAt");
11325  }
11326  Utilities->CallLogPop(644);
11327  return(InactiveTrackVector.at(At));
11328 }
11329 
11330 // ---------------------------------------------------------------------------
11331 
11332 bool TTrack::BlankElementAt(int Caller, int At) const
11333 {
11334  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
11335  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
11336  {
11337  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
11338  }
11339  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
11340  {
11341  Utilities->CallLogPop(645);
11342  return(true);
11343  }
11344  else
11345  {
11346  Utilities->CallLogPop(646);
11347  return(false);
11348  }
11349 }
11350 
11351 // ---------------------------------------------------------------------------
11352 
11353 bool TTrack::OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
11354 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
11355  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
11356  split is required a specific check is made using ThisStationLongEnoughForSplit.
11357  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
11358  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
11359 */
11360 {
11361  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneStationLongEnoughForSplit," + LocationName);
11362  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11363  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
11364  TLocationNameMultiMapIterator SNIterator;
11365  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11366 
11367  if(SNRange.first == SNRange.second)
11368  {
11369  Utilities->CallLogPop(972);
11370  return(false); // should have been caught earlier but include for completeness
11371  }
11372  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11373  {
11374  if(SNIterator->second < 0)
11375  {
11376  continue; // exclude footcrossings
11377  }
11378  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
11379  if(InactiveElement.TrackType == Concourse)
11380  {
11381  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11382  }
11383  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11384  {
11385  continue; // only interested in locations where ActiveTrackElementName may be set
11386  }
11387  THVPair HVPair;
11388  HVPair.first = InactiveElement.HLoc;
11389  HVPair.second = InactiveElement.VLoc;
11390  if(TrackMap.find(HVPair) == TrackMap.end())
11391  {
11392  throw Exception
11393  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneStationLongEnoughForSplit (1)");
11394  }
11395  int TVPos = TrackMap.find(HVPair)->second;
11396  FirstNamedElement = TrackElementAt(560, TVPos);
11397  // first check linked on both sides, skip the check if not
11398  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
11399  {
11400  continue;
11401  }
11402  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
11403  // ActiveTrackElementNames are points and excluding trailing connections for points
11404  FirstNamedExitPos = 0;
11405  {
11406  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
11407  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11408  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11409  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11410  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11411  {
11412  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11413  {
11414  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
11415  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11416  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11417  // success, now check FirstNamedElement link not trailing points & if so all OK
11418  {
11419  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11420  {
11421  Utilities->CallLogPop(1002);
11422  return(true);
11423  }
11424  }
11425  }
11426  }
11427  }
11428  // failed, try link 1
11429  FirstNamedExitPos = 1;
11430  {
11431  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
11432  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
11433  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
11434  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
11435  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
11436  {
11437  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11438  {
11439  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
11440  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
11441  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
11442  // success, now check FirstNamedElement link not trailing points & if so all OK
11443  {
11444  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
11445  {
11446  Utilities->CallLogPop(1003);
11447  return(true);
11448  }
11449  }
11450  }
11451  }
11452  }
11453  }
11454  Utilities->CallLogPop(1004);
11455  return(false);
11456 }
11457 
11458 // ---------------------------------------------------------------------------
11459 
11460 bool TTrack::OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName) //changed at v2.18.0
11461 /* Check sufficient active elements at same H & V as the non-station element with same ActiveTrackElementName linked together to allow a train split.
11462  Only one train length is needed to return true, but this doesn't mean that all tracks at the location are long enough. When a
11463  split is required a specific check is made using ThisLocationLongEnoughForSplit.
11464  Need at least two linked ActiveTrackElementNames, with connected elements at each end, or three if one end is a buffer, but no need to check
11465  buffers explicitly as it will come out automatically with the logic applied.
11466  Note that these conditions exclude opposed buffers since these not linked.
11467 */
11468 {
11469  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNonStationLongEnoughForSplit," + LocationName);
11470  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
11471  int FirstNamedExitPos, SecondNamedEntryPos, SecondNamedExitPos;
11472  TLocationNameMultiMapIterator SNIterator;
11473  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11474 
11475  if(SNRange.first == SNRange.second)
11476  {
11477  Utilities->CallLogPop(2641);
11478  return(false); // should have been caught earlier but include for completeness
11479  }
11480  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11481  {
11482  if(SNIterator->second < 0) //negative numbers represent active track elements
11483  {
11484  continue; // exclude footcrossings - only these have active track element names
11485  }
11486  InactiveElement = InactiveTrackElementAt(1412, SNIterator->second);
11487  if(InactiveElement.TrackType == Concourse)
11488  {
11489  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
11490  }
11491  if(!TrackElementPresentAtHV(2, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
11492  {
11493  continue; // only interested in locations where ActiveTrackElementName may be set
11494  }
11495  THVPair HVPair;
11496  HVPair.first = InactiveElement.HLoc;
11497  HVPair.second = InactiveElement.VLoc;
11498  if(TrackMap.find(HVPair) == TrackMap.end())
11499  {
11500  throw Exception ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNonStationLongEnoughForSplit(1)");
11501  }
11502  int TVPos = TrackMap.find(HVPair)->second;
11503  FirstNamedElement = TrackElementAt(1610, TVPos);
11504  // first check linked on both sides, skip the check if not
11505  if(((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) && ((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)))
11506  {
11507  continue;
11508  }
11509  // check if another ActiveTrackElementName connected via a link
11510  if((FirstNamedElement.Conn[2] == -1) || (FirstNamedElement.Conn[3] == -1)) //examine connections at links 0 & 1
11511  {
11512  FirstNamedExitPos = 0; //this is the end linked to the second named element
11513  {
11514  SecondNamedElement = TrackElementAt(1611, FirstNamedElement.Conn[FirstNamedExitPos]);
11515  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11516  {
11517  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11518  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11519  {
11520  SecondNamedExitPos = 1 - SecondNamedEntryPos; //SecondNamedExitPos is the end not linked to FirstNamedElement
11521  }
11522  else if(SecondNamedEntryPos == 2)
11523  {
11524  SecondNamedExitPos = 3;
11525  }
11526  else if(SecondNamedEntryPos == 3)
11527  {
11528  SecondNamedExitPos = 2;
11529  }
11530  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11531  {
11532  Utilities->CallLogPop(2642);
11533  return(true);
11534  } //if not try other exitpos
11535  }
11536  }
11537  FirstNamedExitPos = 1;
11538  {
11539  SecondNamedElement = TrackElementAt(1612, FirstNamedElement.Conn[FirstNamedExitPos]);
11540  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11541  {
11542  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11543  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11544  {
11545  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11546  }
11547  else if(SecondNamedEntryPos == 2)
11548  {
11549  SecondNamedExitPos = 3;
11550  }
11551  else if(SecondNamedEntryPos == 3)
11552  {
11553  SecondNamedExitPos = 2;
11554  }
11555  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11556  {
11557  Utilities->CallLogPop(2643);
11558  return(true);
11559  } //failed so far, try links 2 & 3, one or other must be linked on both side or would have continued
11560  }
11561  }
11562  }
11563  else if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1)) //examine connections at links 2 & 3
11564  {
11565  FirstNamedExitPos = 2;
11566  {
11567  SecondNamedElement = TrackElementAt(1613, FirstNamedElement.Conn[FirstNamedExitPos]);
11568  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11569  {
11570  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11571  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11572  {
11573  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11574  }
11575  else if(SecondNamedEntryPos == 2)
11576  {
11577  SecondNamedExitPos = 3;
11578  }
11579  else if(SecondNamedEntryPos == 3)
11580  {
11581  SecondNamedExitPos = 2;
11582  }
11583  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11584  {
11585  Utilities->CallLogPop(2644);
11586  return(true);
11587  } //if not try other exitpos
11588  }
11589  }
11590  FirstNamedExitPos = 3;
11591  {
11592  SecondNamedElement = TrackElementAt(1614, FirstNamedElement.Conn[FirstNamedExitPos]);
11593  if(SecondNamedElement.ActiveTrackElementName == LocationName) //so far so good, check if linked on other side and if so return true
11594  {
11595  SecondNamedEntryPos = FirstNamedElement.ConnLinkPos[FirstNamedExitPos];
11596  if((SecondNamedEntryPos == 0) || (SecondNamedEntryPos == 1))
11597  {
11598  SecondNamedExitPos = 1 - SecondNamedEntryPos;
11599  }
11600  else if(SecondNamedEntryPos == 2)
11601  {
11602  SecondNamedExitPos = 3;
11603  }
11604  else if(SecondNamedEntryPos == 3)
11605  {
11606  SecondNamedExitPos = 2;
11607  }
11608  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
11609  {
11610  Utilities->CallLogPop(2645);
11611  return(true);
11612  } //failed so continue to next element or return false
11613  }
11614  }
11615  }
11616  }
11617  Utilities->CallLogPop(2646);
11618  return(false);
11619 }
11620 
11621 // ---------------------------------------------------------------------------
11622 
11623 //new version at v2.18.0
11624 bool TTrack::ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement,
11625  int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
11626 /* Return false if the track that the train is on isn't long enough for a split - only 1 named element or 2 with only one external link.
11627 Otherwise find the best 4 final element positions, preferably with FrontTrainFrontPos on a named element. Conditions are that the original train
11628 will lie within the 4 elements of the two split trains, and at least 1 element of each split train will be at the location. Within those conditions
11629 the lead element of the front train will be at the location if it is possible.
11630 */
11631 {
11632  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisLocationLongEnoughForSplit," + AnsiString(TrainID) + "," +
11633  LocationName + AnsiString(LeadElement) + "," + AnsiString(LeadExitPos) + "," + AnsiString(MidElement) + "," + AnsiString(MidEntryPos));
11634 
11635  TemporaryDelay = false; //used in calling function to set LastActionTime to TTClockTime so failure messages only given every 30 secs
11636  //count forwards from LeadElement - only need to count forwards 2 elements to ptovide for room for new front train
11637  int FwdPos[3] = {LeadElement, -1, -1}; //0 starts at LeadElement and increases as go forwards
11638  int RwdPos[3] = {MidElement, -1, -1}; //0 starts at MidElement and increases as go backwards
11639  TTrackElement FwdPos0Element = TrackElementAt(1666, LeadElement);
11640  TTrackElement RwdPos0Element = TrackElementAt(1667, MidElement);
11641  int FwdPos1EntryPos, FwdPos1ExitPos, FwdPos2EntryPos, FwdPos2ExitPos, RwdPos1EntryPos, RwdPos1ExitPos, RwdPos2EntryPos, RwdPos2ExitPos; //these needed to test for other train on element
11642 
11643  bool FwdDerail1 = false, FwdDerail2 = false, RwdDerail1 = false, RwdDerail2 = false;
11644  int NumFwdNamedElements = 0, NumFwdElements = 0, NumRwdNamedElements = 0, NumRwdElements = 1; //Fwd = ahead of LeadElement, Rwd includes MidElement
11645  if(RwdPos0Element.ActiveTrackElementName == LocationName) //MidElement
11646  {
11647  NumRwdNamedElements = 1;
11648  }
11649 
11650  FwdPos[1] = FwdPos0Element.Conn[LeadExitPos];
11651  if(FwdPos[1] > -1)
11652  {
11653  NumFwdElements = 1;
11654  TTrackElement FwdPos1Element = TrackElementAt(1668, FwdPos[1]);
11655  if(FwdPos1Element.ActiveTrackElementName == LocationName)
11656  {
11657  NumFwdNamedElements = 1;
11658  }
11659  FwdPos1EntryPos = FwdPos0Element.ConnLinkPos[LeadExitPos];
11660  FwdPos1ExitPos = GetAnyElementOppositeLinkPos(4, FwdPos[1], FwdPos1EntryPos, FwdDerail1);
11661  FwdPos[2] = FwdPos1Element.Conn[FwdPos1ExitPos];
11662  if(FwdPos[2] > -1)
11663  {
11664  NumFwdElements = 2;
11665  FwdPos2EntryPos = FwdPos1Element.ConnLinkPos[FwdPos1ExitPos];
11666  FwdPos2ExitPos = GetAnyElementOppositeLinkPos(5, FwdPos[2], FwdPos2EntryPos, FwdDerail2); //this is purely to obtain Derail
11667  TTrackElement FwdPos2Element = TrackElementAt(1669, FwdPos[2]);
11668  if(FwdPos2Element.ActiveTrackElementName == LocationName)
11669  {
11670  NumFwdNamedElements = 2;
11671  }
11672  }
11673  }
11674 //this is as far as need to go forwards
11675 
11676  RwdPos[1] = RwdPos0Element.Conn[MidEntryPos];
11677  if(RwdPos[1] > -1)
11678  {
11679  NumRwdElements = 2; //includes MidElement
11680  TTrackElement RwdPos1Element = TrackElementAt(1670, RwdPos[1]);
11681  if(RwdPos1Element.ActiveTrackElementName == LocationName)
11682  {
11683  NumRwdNamedElements = 2; //includes MidElement (treats MidElement as named even if not, as eventual positions will be same either way)
11684  }
11685  RwdPos1ExitPos = RwdPos0Element.ConnLinkPos[MidEntryPos];
11686  RwdPos1EntryPos = GetAnyElementOppositeLinkPos(6, RwdPos[1], RwdPos1ExitPos, RwdDerail1);
11687  RwdPos[2] = RwdPos1Element.Conn[RwdPos1EntryPos];
11688  if(RwdPos[2] > -1)
11689  {
11690  NumRwdElements = 3; //includes MidElement
11691  RwdPos2ExitPos = RwdPos1Element.ConnLinkPos[RwdPos1EntryPos];
11692  RwdPos2EntryPos = GetAnyElementOppositeLinkPos(7, RwdPos[2], RwdPos2ExitPos, RwdDerail2); //this is purely to obtain Derail
11693  TTrackElement RwdPos2Element = TrackElementAt(1671, RwdPos[2]);
11694  if(RwdPos2Element.ActiveTrackElementName == LocationName)
11695  {
11696  NumRwdNamedElements = 3; //includes MidElement (treats MidElement & next position to rear as both named even if not, as eventual positions will be same either way)
11697  }
11698  }
11699  }
11700 //this is as far as need to go backwards
11701 
11702 //now try to accommodate front train on named elements if possible
11703  if(NumFwdNamedElements == 2)//Front train moves onto the 2 forward named elements & rear train is on original train elements X N N N (N = named, X = named or not)
11704  { // M L - - >> RM RL FM FL
11705  FrontTrainFrontPos = FwdPos[2];
11706  FrontTrainRearPos = FwdPos[1];
11707  RearTrainFrontPos = LeadElement;
11708  RearTrainRearPos = MidElement;
11709  if(FwdDerail1 || FwdDerail2)
11710  {
11711  TrainController->StopTTClockMessage(159, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11712  TemporaryDelay = true;
11713  Utilities->CallLogPop(2661); //may be able to split further back but leave as is to avoid complication
11714  return(true);
11715  }
11716  if(OtherTrainOnTrack(6, FwdPos[1], FwdPos1EntryPos, TrainID))
11717  {
11718  TrainController->StopTTClockMessage(160, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11719  TemporaryDelay = true;
11720  Utilities->CallLogPop(2662); //may be able to split further back but leave as is to avoid complication
11721  return(true);
11722  }
11723  if(OtherTrainOnTrack(7, FwdPos[2], FwdPos2ExitPos, TrainID))
11724  {
11725  TrainController->StopTTClockMessage(161, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11726  TemporaryDelay = true;
11727  Utilities->CallLogPop(2663); //may be able to split further back but leave as is to avoid complication
11728  return(true);
11729  }
11730  Utilities->CallLogPop(2664);
11731  return(true);
11732  }
11733 
11734  else if((NumFwdNamedElements == 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11735  { //Front train moves onto the 1 forward named element & rear train occupies 1 element behind original train - M L - >> RM RL FM FL
11736  FrontTrainFrontPos = FwdPos[1];
11737  FrontTrainRearPos = LeadElement;
11738  RearTrainFrontPos = MidElement;
11739  RearTrainRearPos = RwdPos[1];
11740  if(FwdDerail1)
11741  {
11742  TrainController->StopTTClockMessage(162, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11743  TemporaryDelay = true;
11744  Utilities->CallLogPop(2665); //may be able to split further back but leave as is to avoid complication
11745  return(true);
11746  }
11747  if(RwdDerail1)
11748  {
11749  TrainController->StopTTClockMessage(163, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11750  TemporaryDelay = true;
11751  Utilities->CallLogPop(2666); //may be able to split further back but leave as is to avoid complication
11752  return(true);
11753  }
11754  if(OtherTrainOnTrack(8, FwdPos[1], FwdPos1EntryPos, TrainID))
11755  {
11756  TrainController->StopTTClockMessage(164, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11757  TemporaryDelay = true;
11758  Utilities->CallLogPop(2667); //may be able to split further back but leave as is to avoid complication
11759  return(true);
11760  }
11761  if(OtherTrainOnTrack(9, RwdPos[1], RwdPos1ExitPos, TrainID))
11762  {
11763  TrainController->StopTTClockMessage(165, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11764  TemporaryDelay = true;
11765  Utilities->CallLogPop(2668); //may be able to split further back but leave as is to avoid complication
11766  return(true);
11767  }
11768  Utilities->CallLogPop(2669);
11769  return(true);
11770  }
11771 
11772  else if((NumRwdNamedElements >= 2) && (NumRwdElements == 3)) //Rwd includes MidElement X N N N (N = named, X = named or not but connected)
11773  {//front train occupies original train position and rear train fits behind it - - M L >> RM RL FM FL
11774  FrontTrainFrontPos = LeadElement;
11775  FrontTrainRearPos = MidElement;
11776  RearTrainFrontPos = RwdPos[1];
11777  RearTrainRearPos = RwdPos[2];
11778  if(RwdDerail1 || RwdDerail2)
11779  {
11780  TrainController->StopTTClockMessage(166, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11781  TemporaryDelay = true;
11782  Utilities->CallLogPop(2670); //may be able to split further back but leave as is to avoid complication
11783  return(true);
11784  }
11785  if(OtherTrainOnTrack(10, RwdPos[1], RwdPos1ExitPos, TrainID))
11786  {
11787  TrainController->StopTTClockMessage(167, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11788  TemporaryDelay = true;
11789  Utilities->CallLogPop(2671); //may be able to split further back but leave as is to avoid complication
11790  return(true);
11791  }
11792  if(OtherTrainOnTrack(11, RwdPos[2], RwdPos2EntryPos, TrainID))
11793  {
11794  TrainController->StopTTClockMessage(168, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11795  TemporaryDelay = true;
11796  Utilities->CallLogPop(2672); //may be able to split further back but leave as is to avoid complication
11797  return(true);
11798  }
11799  Utilities->CallLogPop(2673);
11800  return(true);
11801  }
11802 
11803 //here look for front overhang situations
11804  else if((NumFwdNamedElements == 1) && (NumFwdElements == 2)) // X N N X (N = named, X = named or not but connected)
11805  { // M L - - >> RM RL FM FL
11806  FrontTrainFrontPos = FwdPos[2];
11807  FrontTrainRearPos = FwdPos[1];
11808  RearTrainFrontPos = LeadElement;
11809  RearTrainRearPos = MidElement;
11810  if(FwdDerail1 || FwdDerail2)
11811  {
11812  TrainController->StopTTClockMessage(169, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11813  TemporaryDelay = true;
11814  Utilities->CallLogPop(2674); //may be able to split further back but leave as is to avoid complication
11815  return(true);
11816  }
11817  if(OtherTrainOnTrack(12, FwdPos[1], FwdPos1EntryPos, TrainID))
11818  {
11819  TrainController->StopTTClockMessage(170, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11820  TemporaryDelay = true;
11821  Utilities->CallLogPop(2675); //may be able to split further back but leave as is to avoid complication
11822  return(true);
11823  }
11824  if(OtherTrainOnTrack(13, FwdPos[2], FwdPos2ExitPos, TrainID))
11825  {
11826  TrainController->StopTTClockMessage(171, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11827  TemporaryDelay = true;
11828  Utilities->CallLogPop(2676); //may be able to split further back but leave as is to avoid complication
11829  return(true);
11830  }
11831  Utilities->CallLogPop(2677);
11832  return(true);
11833  }
11834 
11835  else if((NumFwdElements >= 1) && (NumRwdNamedElements >= 1) && (NumRwdElements >= 2)) // X N N X (N = named, X = named or not but connected)
11836  { // - M L - >> RM RL FM FL
11837  FrontTrainFrontPos = FwdPos[1];
11838  FrontTrainRearPos = LeadElement;
11839  RearTrainFrontPos = MidElement;
11840  RearTrainRearPos = RwdPos[1];
11841  if(FwdDerail1)
11842  {
11843  TrainController->StopTTClockMessage(172, HeadCode + " unable to split at " + LocationName + ", points set wrongly ahead of train. Please change these points to allow the split.");
11844  TemporaryDelay = true;
11845  Utilities->CallLogPop(2678); //may be able to split further back but leave as is to avoid complication
11846  return(true);
11847  }
11848  if(RwdDerail1)
11849  {
11850  TrainController->StopTTClockMessage(173, HeadCode + " unable to split at " + LocationName + ", points set wrongly behind train. Please change these points to allow the split.");
11851  TemporaryDelay = true;
11852  Utilities->CallLogPop(2679); //may be able to split further back but leave as is to avoid complication
11853  return(true);
11854  }
11855  if(OtherTrainOnTrack(14, FwdPos[1], FwdPos1EntryPos, TrainID))
11856  {
11857  TrainController->StopTTClockMessage(174, HeadCode + " unable to split at " + LocationName + " because another train is obstructing ahead of this train. Please move the obstructing train to allow the split.");
11858  TemporaryDelay = true;
11859  Utilities->CallLogPop(2680); //may be able to split further back but leave as is to avoid complication
11860  return(true);
11861  }
11862  if(OtherTrainOnTrack(15, RwdPos[1], RwdPos1ExitPos, TrainID))
11863  {
11864  TrainController->StopTTClockMessage(175, HeadCode + " unable to split at " + LocationName + " because another train is obstructing behind this train. Please move the obstructing train to allow the split.");
11865  TemporaryDelay = true;
11866  Utilities->CallLogPop(2681); //may be able to split further back but leave as is to avoid complication
11867  return(true);
11868  }
11869  Utilities->CallLogPop(2682);
11870  return(true);
11871  }
11872 //anything else fails as location too short
11873  Utilities->CallLogPop(2652);
11874  return(false);
11875 }
11876 
11877 // ---------------------------------------------------------------------------
11878 
11879 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
11880 {
11881  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
11882  TLocationNameMultiMapIterator SNIterator;
11883  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
11884 
11885  if(SNRange.first != SNRange.second)
11886  {
11887  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
11888  {
11889  if(SNIterator->second < 0)
11890  {
11891  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
11892  }
11893  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
11894  SNIterator->second).TrackType == NamedNonStationLocation))
11895  {
11896  Utilities->CallLogPop(1121);
11897  return(true);
11898  }
11899  }
11900  }
11901  Utilities->CallLogPop(848);
11902  return(false);
11903 }
11904 
11905 // ---------------------------------------------------------------------------
11906 
11907 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
11908 {
11909 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
11910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11911  "," + AnsiString(SpeedTag));
11912  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
11913  {
11914  Utilities->CallLogPop(949);
11915  return(false);
11916  }
11917  bool FoundFlag;
11918  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
11919 
11920  if(!FoundFlag)
11921  {
11922  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
11923  }
11924  TTrackElement IAElement;
11925 
11926  if(SpeedTag == 68) // top sig
11927  {
11928  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
11929  {
11930  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
11931  {
11932  IAElement = InactiveTrackElementAt(50, IMPair.first);
11933  }
11934  else
11935  {
11936  IAElement = InactiveTrackElementAt(51, IMPair.second);
11937  }
11938  if(IAElement.LocationName == "")
11939  {
11940 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
11941  SignalPlatformGraphic = RailGraphics->gl76Striped;
11942  }
11943  else
11944  {
11945 // SignalPlatformGraphic = RailGraphics->Plat68;
11946  SignalPlatformGraphic = RailGraphics->gl76;
11947  }
11948  Utilities->CallLogPop(950);
11949  return(true);
11950  }
11951  }
11952  else if(SpeedTag == 69) // bot sig
11953  {
11954  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
11955  {
11956  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
11957  {
11958  IAElement = InactiveTrackElementAt(77, IMPair.first);
11959  }
11960  else
11961  {
11962  IAElement = InactiveTrackElementAt(78, IMPair.second);
11963  }
11964  if(IAElement.LocationName == "")
11965  {
11966 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
11967  SignalPlatformGraphic = RailGraphics->bm77Striped;
11968  }
11969  else
11970  {
11971 // SignalPlatformGraphic = RailGraphics->Plat69;
11972  SignalPlatformGraphic = RailGraphics->bm77;
11973  }
11974  Utilities->CallLogPop(951);
11975  return(true);
11976  }
11977  }
11978  else if(SpeedTag == 70) // left sig
11979  {
11980  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
11981  {
11982  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
11983  {
11984  IAElement = InactiveTrackElementAt(55, IMPair.first);
11985  }
11986  else
11987  {
11988  IAElement = InactiveTrackElementAt(82, IMPair.second);
11989  }
11990  if(IAElement.LocationName == "")
11991  {
11992 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
11993  SignalPlatformGraphic = RailGraphics->bm78Striped;
11994  }
11995  else
11996  {
11997 // SignalPlatformGraphic = RailGraphics->Plat70;
11998  SignalPlatformGraphic = RailGraphics->bm78;
11999  }
12000  Utilities->CallLogPop(952);
12001  return(true);
12002  }
12003  }
12004  else if(SpeedTag == 71) // right sig
12005  {
12006  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
12007  {
12008  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
12009  {
12010  IAElement = InactiveTrackElementAt(85, IMPair.first);
12011  }
12012  else
12013  {
12014  IAElement = InactiveTrackElementAt(86, IMPair.second);
12015  }
12016  if(IAElement.LocationName == "")
12017  {
12018 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
12019  SignalPlatformGraphic = RailGraphics->gl79Striped;
12020  }
12021  else
12022  {
12023 // SignalPlatformGraphic = RailGraphics->Plat71;
12024  SignalPlatformGraphic = RailGraphics->gl79;
12025  }
12026  Utilities->CallLogPop(953);
12027  return(true);
12028  }
12029  }
12030  Utilities->CallLogPop(954);
12031  return(false);
12032 }
12033 
12034 // ---------------------------------------------------------------------------
12035 
12036 bool TTrack::OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
12037 // returns true if another train on LinkPos track of element at TrackPos, whether bridge or not, return false if not, or if TrackPos == -1,
12038 // or LinkPos == -1, or if only own train on the track. LinkPos can be entry or exit.
12039 {
12040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(TrackPos) + "," +
12041  AnsiString(LinkPos) + "," + AnsiString(OwnTrainID));
12042  if((LinkPos < 0) || (TrackPos < 0))
12043  {
12044  Utilities->CallLogPop(1348);
12045  return(false);
12046  }
12047  TTrackElement TrackElement = TrackElementAt(713, TrackPos);
12048 
12049  if(TrackElement.TrackType != Bridge)
12050  {
12051  Utilities->CallLogPop(1349);
12052  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
12053  }
12054 // bridge if reach here
12055  if(LinkPos > 1)
12056  {
12057  Utilities->CallLogPop(1350);
12058  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 != OwnTrainID));
12059  }
12060  else
12061  {
12062  Utilities->CallLogPop(1351);
12063  return ((TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1) && (TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 != OwnTrainID));
12064  }
12065 }
12066 
12067 // ---------------------------------------------------------------------------
12068 
12070 {
12071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
12072  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
12073  {
12074  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
12075  }
12076  Utilities->CallLogPop(1483);
12077  return(SelectVector.at(At));
12078 }
12079 
12080 // ---------------------------------------------------------------------------
12081 
12082 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
12083 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
12084 {
12085  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
12086  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
12087  bool FoundFlag = false;
12088  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
12089  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
12090 
12091  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
12092  Utilities->CallLogPop(1538);
12093  return(FoundFlag);
12094 }
12095 
12096 // ---------------------------------------------------------------------------
12097 
12098 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
12099 {
12100 // return true if find an inactive element called 'Name'
12101  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
12102  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
12103  bool FoundFlag = false;
12104 
12105  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12106  {
12107  if(InactiveTrackElementAt(158, x).LocationName == Name)
12108  {
12109  FoundFlag = true;
12110  int V = InactiveTrackElementAt(159, x).VLoc;
12111  int H = InactiveTrackElementAt(160, x).HLoc;
12112  if(V > VLocHi)
12113  {
12114  VLocHi = V;
12115  }
12116  if(V < VLocLo)
12117  {
12118  VLocLo = V;
12119  }
12120  if(H < HLoc)
12121  {
12122  HLoc = H;
12123  }
12124  }
12125  }
12126  if(FoundFlag)
12127  {
12128  VPosHi = 16 * VLocHi;
12129  VPosLo = 16 * VLocLo;
12130  HPos = 16 * HLoc;
12131  Utilities->CallLogPop(1562);
12132  return(true);
12133  }
12134  else
12135  {
12136  Utilities->CallLogPop(1563);
12137  return(false);
12138  }
12139 }
12140 
12141 // ---------------------------------------------------------------------------
12142 
12143 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
12144 {
12145 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
12146 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
12147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
12148  AnsiString(EndTVPosition));
12149  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
12150  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
12151 
12152 // get H & V values for the element adjacent to Link[0] & Link[1]
12153  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
12154  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
12155  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
12156  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
12157 
12158 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
12159  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
12160  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
12161  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
12162  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
12163 
12164  if(Link0Squares <= Link1Squares)
12165  {
12166  Utilities->CallLogPop(1851);
12167  return(0);
12168  }
12169  else
12170  {
12171  Utilities->CallLogPop(1852);
12172  return(1);
12173  }
12174 }
12175 
12176 // ---------------------------------------------------------------------------
12177 
12178 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
12179 {
12180  // element can be points or any other type
12181  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
12182  AnsiString(LinkPos));
12183  Derail = false;
12184  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
12185 
12186  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
12187  {
12188  if(TE.Attribute == 0)
12189  {
12190  Utilities->CallLogPop(663);
12191  return(1); // Att == 0 & ExitPos == 1 represent straight
12192  }
12193  else
12194  {
12195  Utilities->CallLogPop(664);
12196  return(3); // Att == 1 & ExitPos == 3 represent diverging
12197  }
12198  }
12199  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
12200  {
12201  if((LinkPos == 1) && (TE.Attribute == 0))
12202  {
12203  Utilities->CallLogPop(665);
12204  return(0); // Att == 0 represents straight
12205  }
12206  else if(LinkPos == 1)
12207  {
12208  Derail = true;
12209  Utilities->CallLogPop(666);
12210  return(0);
12211  }
12212  else if((LinkPos == 3) && (TE.Attribute == 1))
12213  {
12214  Utilities->CallLogPop(667);
12215  return(0);
12216  }
12217  else if(LinkPos == 3)
12218  {
12219  Derail = true;
12220  Utilities->CallLogPop(668);
12221  return(0);
12222  }
12223  }
12224  else if(LinkPos == 0)
12225  {
12226  Utilities->CallLogPop(669);
12227  return(1);
12228  }
12229  else if(LinkPos == 1)
12230  {
12231  Utilities->CallLogPop(670);
12232  return(0);
12233  }
12234  else if(LinkPos == 2)
12235  {
12236  Utilities->CallLogPop(671);
12237  return(3);
12238  }
12239  else if(LinkPos == 3)
12240  {
12241  Utilities->CallLogPop(672);
12242  return(2);
12243  }
12244  throw Exception("Error, failure in GetExitPos"); // should never reach here
12245 }
12246 
12247 // ----------------------------------------------------------------------------
12248 
12250 {
12251  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
12252  LCVector.clear();
12253  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
12254  {
12255  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
12256  {
12257  LCVector.push_back(x);
12258  }
12259  }
12260  Utilities->CallLogPop(1931);
12261  return;
12262 }
12263 
12264 // ---------------------------------------------------------------------------
12265 
12266 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
12267 /*
12268  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
12269  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
12270  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
12271  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
12272 */
12273 {
12274  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
12275  AnsiString(Link));
12276  bool FoundFlag;
12277 
12278  TrainID = -1;
12279  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
12280 
12281  if(!FoundFlag)
12282  {
12283  Utilities->CallLogPop(2001);
12284  return(false);
12285  }
12286  TTrackElement TE = TrackElementAt(882, VecPos);
12287 
12288  TrainID = TE.TrainIDOnElement;
12289  if(TE.TrackType == Bridge)
12290  {
12291  if(TE.TrainIDOnElement > -1)
12292  {
12293  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
12294  {
12296  }
12297  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
12298  {
12300  }
12301  else
12302  {
12303  TrainID = -1; // shouldn't ever reach here but be safe
12304  }
12305  }
12306  }
12307  if(TrainID == -1)
12308  {
12309  Utilities->CallLogPop(2002);
12310  return(false);
12311  }
12312 // now get the train
12313  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
12314 
12315  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
12316  {
12317  Utilities->CallLogPop(2003);
12318  return(true);
12319  }
12320  TrainID = -1;
12321  Utilities->CallLogPop(2004);
12322  return(false);
12323 }
12324 
12325 // ---------------------------------------------------------------------------
12326 
12327 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
12328 /* New at v1.2.0
12329  As DiagonalFouledByRouteOrTrain but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
12330  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
12331  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
12332  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
12333  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
12334  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
12335  Each of these is examined in turn for each route element in the relevant position.
12336 */
12337 {
12338  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
12339  "," + AnsiString(DiagonalLinkNumber));
12340  TrainID = -1;
12341  TPrefDirElement TempPrefDirElement;
12342  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
12343  //first check if the DiagonalLinkNumber is itself a buffer/Gap/Continuation and if so return false
12344  TTrackElement TE = GetTrackElementFromTrackMap(6, HLoc, VLoc);
12345  if(((TE.TrackType == Buffers) || (TE.TrackType == GapJump) || (TE.TrackType == Continuation)) && (TE.Link[0] == DiagonalLinkNumber))
12346  {
12347  Utilities->CallLogPop(2747);
12348  return(false);
12349  }
12350  int H = HLoc - 1;
12351  int V = VLoc;
12352  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, H, V, 3, TrainID) && !(DiagAtLinkIsBufGapCont(40, H, V, 3)))
12353  || ((DiagonalLinkNumber == 7) && TrainOnLink(9, H, V, 9, TrainID) && !(DiagAtLinkIsBufGapCont(41, H, V, 9))))
12354  {
12355  Utilities->CallLogPop(2027);
12356  return(true);
12357  }
12358  H = HLoc;
12359  V = VLoc - 1;
12360  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, H, V, 7, TrainID) && !(DiagAtLinkIsBufGapCont(42, H, V, 7)))
12361  || ((DiagonalLinkNumber == 3) && TrainOnLink(11, H, V, 9, TrainID) && !(DiagAtLinkIsBufGapCont(43, H, V, 9))))
12362  {
12363  Utilities->CallLogPop(2028);
12364  return(true);
12365  }
12366  H = HLoc + 1;
12367  V = VLoc;
12368  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, H, V, 1, TrainID) && !(DiagAtLinkIsBufGapCont(44, H, V, 1)))
12369  || ((DiagonalLinkNumber == 9) && TrainOnLink(13, H, V, 7, TrainID) && !(DiagAtLinkIsBufGapCont(45, H, V, 7))))
12370  {
12371  Utilities->CallLogPop(2029);
12372  return(true);
12373  }
12374  H = HLoc;
12375  V = VLoc + 1;
12376  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, H, V, 1, TrainID) && !(DiagAtLinkIsBufGapCont(46, H, V, 1)))
12377  || ((DiagonalLinkNumber == 9) && TrainOnLink(15, H, V, 3, TrainID) && !(DiagAtLinkIsBufGapCont(47, H, V, 3))))
12378  {
12379  Utilities->CallLogPop(2030);
12380  return(true);
12381  }
12382  Utilities->CallLogPop(2031);
12383  return(false);
12384 }
12385 
12386 // ---------------------------------------------------------------------------
12387 
12388 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
12389 {
12390  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
12391  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
12392  TUserGraphicItem UGI;
12393  AnsiString JustFileName = "";
12394 
12395  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
12396  {
12397  UGI = UserGraphicVectorAt(17, x);
12398  int LastDelim = UGI.FileName.LastDelimiter('\\');
12399  if(LastDelim == 0) // can't find it so skip this item
12400  {
12401  continue;
12402  }
12403  else
12404  {
12405  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
12406  }
12407  Utilities->SaveFileString(VecFile, JustFileName);
12408  Utilities->SaveFileInt(VecFile, UGI.HPos);
12409  Utilities->SaveFileInt(VecFile, UGI.VPos);
12410  }
12411  Utilities->CallLogPop(2178);
12412 }
12413 
12414 // ---------------------------------------------------------------------------
12415 
12416 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
12417 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
12418 {
12419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
12420  int NumPlats = 0;
12421  TTrackElement TempElement;
12422  int TempInt;
12423 
12424  typedef std::list<int> TNamePosList;
12425  TNamePosList NamePosList;
12426  typedef TNamePosList::iterator TNPLIt;
12427  TNPLIt NPLIt;
12428  typedef std::list<int> TOnePlatList;
12429  TOnePlatList OnePlatList;
12430  typedef TOnePlatList::iterator TOPLIt;
12431  TOPLIt OPLIt;
12432 
12433  NamePosList.clear();
12434  OnePlatList.clear();
12435  for(unsigned int x = 0; x < TrackVector.size(); x++)
12436  {
12437  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
12438  {
12439  NamePosList.push_back(x);
12440  }
12441  }
12442  //NamePosList complete
12443 
12444  if(!NamePosList.empty()) //first value for the loop examination
12445  {
12446  OnePlatList.push_back(NamePosList.back());
12447  NamePosList.pop_back(); //erase from NPV as done with it here
12448  }
12449  while(!OnePlatList.empty()) //loop to examine all linked elements
12450  {
12451  TempInt = OnePlatList.front();
12452  TempElement = TrackElementAt(989, TempInt);
12453 
12454  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
12455  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
12456  {
12457  OnePlatList.push_back(TempElement.Conn[0]);
12458  NamePosList.erase(NPLIt);
12459  }
12460  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
12461  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
12462  {
12463  OnePlatList.push_back(TempElement.Conn[1]);
12464  NamePosList.erase(NPLIt);
12465  }
12466  //here when loaded any connecting links into OnePlatList, so can erase the front element
12467  OnePlatList.erase(OnePlatList.begin());
12468  if(OnePlatList.empty())
12469  {
12470  NumPlats++; //finished with current linked elements so can increment NumPlats
12471  if(!NamePosList.empty())
12472  {
12473  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
12474  NamePosList.pop_back(); //erase from NPV as done with it there
12475  }
12476  }
12477  }
12478  Utilities->CallLogPop(2218);
12479  return(NumPlats);
12480 }
12481 
12482 // ---------------------------------------------------------------------------
12483 
12484 void TTrack::RepairFailedSignals(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12485 {//repair Signals pointed to by FPVIt
12486  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedSignals," + AnsiString(FPVIt->TVPos));
12487  TTrackElement &TE = Track->TrackElementAt(1516, FPVIt->TVPos);
12488  if(TE.TrackType != SignalPost)
12489  {
12490  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not signal in RepairFailedSignals");
12491  }
12492  if(!TE.Failed)
12493  {
12494  throw Exception("Signals not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedSignals");
12495  }
12496  TE.Failed = false;
12497  //set to correct aspect
12498  int RouteNumber;
12499  if(AllRoutes->GetRouteTypeAndNumber(40, FPVIt->TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
12500  { // 0 for LinkPos ok as a signal so only one track
12501  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(11);
12502  }
12503  //erase from vector
12504  Track->FailedSignalsVector.erase(FPVIt);
12505 
12506  Display->WarningLog(20, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12507  PerfLogForm->PerformanceLog(43, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal at " + TE.ElementID + " restored to full working order");
12508  TrainController->StopTTClockMessage(130, "Signal at " + TE.ElementID + " restored to full working order.");
12509  AllRoutes->RebuildRailwayFlag = true;
12510  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot Signals without failed graphic
12511  Utilities->CallLogPop(2519);
12512 }
12513 
12514 // ---------------------------------------------------------------------------
12515 
12516 void TTrack::RepairFailedPoints(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12517 {//repair points pointed to by FPVIt
12518  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairFailedPoints," + AnsiString(FPVIt->TVPos));
12519  TTrackElement &TE = Track->TrackElementAt(1505, FPVIt->TVPos);
12520  if(TE.TrackType != Points)
12521  {
12522  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not points in RepairFailedPoints");
12523  }
12524  if(!TE.Failed)
12525  {
12526  throw Exception("Points not failed at " + AnsiString(FPVIt->TVPos) + " in RepairFailedPoints");
12527  }
12528  TE.Failed = false;
12533  //erase from vector
12534  Track->FailedPointsVector.erase(FPVIt);
12535 
12536  Display->WarningLog(15, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12537  PerfLogForm->PerformanceLog(38, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points at " + TE.ElementID + " restored to full working order");
12538  TrainController->StopTTClockMessage(123, "Points at " + TE.ElementID + " restored to full working order.");
12539  AllRoutes->RebuildRailwayFlag = true;
12540  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12541  Utilities->CallLogPop(2518);
12542 }
12543 
12544 // ---------------------------------------------------------------------------
12545 
12546 void TTrack::RepairTSR(TFailedElementVector::iterator FPVIt) //added at v2.13.0
12547 {//repair TSR pointed to by FPVIt
12548  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",RepairTSR," + AnsiString(FPVIt->TVPos));
12549  TTrackElement &TE = Track->TrackElementAt(1535, FPVIt->TVPos);
12550  if(TE.TrackType != Simple)
12551  {
12552  throw Exception("Element at " + AnsiString(FPVIt->TVPos) + " not simple in RepairFailedPoints");
12553  }
12554  if(!TE.Failed)
12555  {
12556  throw Exception("No TSR at " + AnsiString(FPVIt->TVPos) + " in RepairTSR");
12557  }
12558  TE.Failed = false;
12561  //erase from vector
12562  Track->TSRVector.erase(FPVIt);
12563 
12564  Display->WarningLog(21, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12565  PerfLogForm->PerformanceLog(44, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order");
12566  TrainController->StopTTClockMessage(131, "Temporary Speed Restriction at " + TE.ElementID + " lifted, track restored to full working order.");
12567  AllRoutes->RebuildRailwayFlag = true;
12568  // to force ClearandRebuildRailway at next clock tick if not in zoom-out mode, to plot points without failed graphic
12569  Utilities->CallLogPop(2520);
12570 }
12571 
12572 // ---------------------------------------------------------------------------
12573 
12575 {
12576  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",PopulateSimpleVector");
12577  SimpleVector.clear();
12578  for(unsigned int x = 0; x < TrackVector.size(); x++)
12579  {
12580  if(TrackElementAt(1517, x).TrackType == Simple)
12581  {
12582  SimpleVector.push_back(int(x));
12583  }
12584  }
12585  Utilities->CallLogPop(2521);
12586 }
12587 
12588 // ---------------------------------------------------------------------------
12589 
12590 bool TTrack::DiagAtLinkIsBufGapCont(int Caller, int H, int V, int LinkIn)
12591 //added at v2.23.3 because of errors in Commuterpop's Xmas 2025 candle holder railway - in checking for fouled diagonals had omitted the exclusion of
12592 //buffers, gaps and continuations. This function is now in all associated functions: DiagonalFouledByRoute, DiagonalFouledByTrain, DiagonalFouledByRouteOrTrain
12593 //and PresetAutoRouteDiagonalFouledByTrack
12594 { //returns true if linkIn on H & V is a buffer, gap or continuation
12595  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagAtLinkIsBufGapCont");
12596  TTrackElement TempElement = GetTrackElementFromTrackMap(5, H, V);
12597  if((TempElement.TrackType == Buffers) || (TempElement.TrackType == GapJump) || (TempElement.TrackType == Continuation))
12598  {
12599  if(TempElement.Link[0] == LinkIn)
12600  {
12601  Utilities->CallLogPop(2751);
12602  return true;
12603  }
12604  }
12605  Utilities->CallLogPop(2752);
12606  return false;
12607 }
12608 
12609 // ---------------------------------------------------------------------------
12610 // UserGraphic, PrefDir & Route functions
12611 // ---------------------------------------------------------------------------
12612 
12614 {
12615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
12616  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
12617  {
12618  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
12619  }
12620  Utilities->CallLogPop(2194);
12621  return(UserGraphicVector.at(At));
12622 }
12623 
12624 // ---------------------------------------------------------------------------
12625 
12626 int TOnePrefDir::LastElementNumber(int Caller) const
12627 {
12628  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
12629  int RetVal = PrefDirVector.size() - 1;
12630 
12631  if(RetVal < 0)
12632  {
12633  throw Exception("Return value negative in call to LastElementNumber");
12634  }
12635  Utilities->CallLogPop(114);
12636  return(RetVal);
12637 }
12638 
12639 // ---------------------------------------------------------------------------
12641 {
12642  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
12643  if(PrefDirVector.empty())
12644  {
12645  throw Exception("PrefDirVector empty in call to LastElementPtr");
12646  }
12647  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
12648 
12649  Utilities->CallLogPop(115);
12650  return(RetIT);
12651 }
12652 
12653 // ---------------------------------------------------------------------------
12655 {
12656  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
12657  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12658  {
12659  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
12660  }
12661  Utilities->CallLogPop(116);
12662  return(PrefDirVector.at(At));
12663 }
12664 
12665 // ---------------------------------------------------------------------------
12667 {
12668  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
12669  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
12670  {
12671  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
12672  " in GetModifiablePrefDirElementAt");
12673  }
12674  Utilities->CallLogPop(117);
12675  return(PrefDirVector.at(At));
12676 }
12677 
12678 // ---------------------------------------------------------------------------
12680 {
12681  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
12682  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12683  {
12684  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
12685  }
12686  Utilities->CallLogPop(118);
12687  return(SearchVector.at(At));
12688 }
12689 
12690 // ---------------------------------------------------------------------------
12692 {
12693  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
12694  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
12695  {
12696  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
12697  }
12698  Utilities->CallLogPop(119);
12699  return(SearchVector.at(At));
12700 }
12701 
12702 // ---------------------------------------------------------------------------
12703 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
12704 /*
12705  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
12706  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
12707  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
12708  set in later functions.
12709 */
12710 {
12711  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12712  ClearPrefDir();
12713  int TrackVectorPosition;
12714  TTrackElement TrackElement;
12715 
12716  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12717  {
12718  Utilities->CallLogPop(126);
12719  return(false);
12720  }
12721 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
12722  if(TrackElement.TrackType == Points)
12723  {
12724  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
12725  //it isn't known which trailing edge is the required PrefDir - could use the straight as
12726  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
12727  //best to prevent it to avoid problems
12728  Utilities->CallLogPop(127);
12729  return false;
12730  }
12731 */
12732  TPrefDirElement PrefDirElement(TrackElement);
12733 
12734  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
12735  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
12736  StorePrefDirElement(1, PrefDirElement); // enter first element
12737 // Note that ELink not set even if a buffer or continuation - these set in
12738 // ConvertPrefDirSearchVector after 2nd element added
12739 
12740  Utilities->CallLogPop(128);
12741  return(true);
12742 }
12743 
12744 // ---------------------------------------------------------------------------
12745 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
12746 
12747 /*
12748  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
12749  Examine the last element in the PrefDirVector, if ELink not set (start element) do an immediate
12750  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
12751  with setting the PrefDir vector, & return true.
12752  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
12753  SearchForPrefDir to examine all branches. If succeed set PrefDirVector.
12754  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
12755  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
12756  ConvertPrefDirSearchVector to set PrefDirVector.
12757  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
12758  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
12759  find the required element return false. CheckCount is used to keep track of set values to allow check later.
12760 */
12761 
12762 {
12763  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12764  FinishElement = false;
12765  int TrackVectorPosition;
12766 
12767  TotalSearchCount = 0;
12768  TTrackElement TrackElement, TempTrackElement;
12769 
12770  if(PrefDirVector.size() == 0)
12771  {
12772  Utilities->CallLogPop(129);
12773  return(false);
12774  }
12775  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
12776  {
12777  Utilities->CallLogPop(130);
12778  return(false);
12779  }
12780 // set the search limits using the last stored element in PrefDirVector as the start point
12781 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
12782 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
12783 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
12784 
12785  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
12786 
12787  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
12788  {
12789  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
12790  SearchLimitHighH = TrackElement.HLoc + 15;
12791  }
12792  else
12793  {
12794  SearchLimitLowH = TrackElement.HLoc - 15;
12795  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
12796  }
12797  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
12798  {
12799  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
12800  SearchLimitHighV = TrackElement.VLoc + 15;
12801  }
12802  else
12803  {
12804  SearchLimitLowV = TrackElement.VLoc - 15;
12805  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
12806  }
12807 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
12808  check & TotalSearchCounts check
12809  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
12810  {
12811  ShowMessage("Unable to reach the selected element - too far ahead");
12812  Utilities->CallLogPop(1692);
12813  return false;
12814  }
12815 */
12816 // get last PrefDir element
12817  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
12818  {
12819  // check if TrackElement adjacent to any of the 4 XLinkPos'
12820  for(int x = 0; x < 4; x++)
12821  {
12822  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
12823  {
12824  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
12825  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
12826  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
12827  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
12828  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
12829  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
12830  // shouldn't ever get it in a serious railway though.
12831 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
12832  }
12833  }
12834  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
12835  {
12836  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
12837  SearchVector.clear(); // use this & convert to set all PrefDir element values
12838  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
12839  {
12841  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12842  {
12843  FinishElement = true;
12844  }
12845  Utilities->CallLogPop(131);
12846  return(true);
12847  }
12848  } // not an adjacent element
12849 
12850  // now check each of the 4 possible XLinkPos values
12851  for(int x = 0; x < 4; x++)
12852  {
12853  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
12854  {
12855  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
12856  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
12857  SearchVector.clear();
12858  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
12859  {
12861  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12862  {
12863  FinishElement = true;
12864  }
12865  Utilities->CallLogPop(132);
12866  return(true);
12867  }
12868  }
12869  } // here if checked all possible exits without success
12870  ShowMessage(
12871  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12872  Utilities->CallLogPop(133);
12873  return(false);
12874  }
12875 // dealt above with LastPrefDirElement being the start element (which can be points)
12876 
12877  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
12878  .ELinkPos] == Lead)) // leading point
12879  {
12880  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
12881  {
12882  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
12883  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
12884  // can't be buffers or gap if points
12885  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
12886  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
12887  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
12888  SearchVector.clear();
12889  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
12890  {
12892  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12893  {
12894  FinishElement = true;
12895  }
12896  Utilities->CallLogPop(134);
12897  return(true);
12898  }
12899  }
12900  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
12901  {
12902  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
12903  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
12904  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
12905  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
12906  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
12907  SearchVector.clear();
12908  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
12909  {
12911  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12912  {
12913  FinishElement = true;
12914  }
12915  Utilities->CallLogPop(135);
12916  return(true);
12917  }
12918  }
12919 // above dealt with immediate finds for leading point,
12920 // now deal with ordinary searches for leading point
12921  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
12922  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
12923  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
12924  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
12925  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
12926  SearchVector.clear();
12927  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
12928  {
12930  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12931  {
12932  FinishElement = true;
12933  }
12934  Utilities->CallLogPop(136);
12935  return(true);
12936  }
12937  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
12938  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
12939  // note that CheckCount already increased to allow for XLinkPos & XLink
12940  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
12941  SearchVector.clear();
12942  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
12943  {
12945  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12946  {
12947  FinishElement = true;
12948  }
12949  Utilities->CallLogPop(137);
12950  return(true);
12951  }
12952 // here if failed to find match for leading point
12953  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
12954  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
12955  ShowMessage(
12956  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12957  Utilities->CallLogPop(138);
12958  return(false);
12959  }
12960 // leading point fully dealt with above
12961 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
12962 // separately as covered in ordinary search.
12963 
12964  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
12965  SearchVector.clear();
12966 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
12967  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
12968  {
12970  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
12971  {
12972  FinishElement = true;
12973  }
12974  Utilities->CallLogPop(139);
12975  return(true);
12976  }
12977  ShowMessage(
12978  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
12979  Utilities->CallLogPop(140);
12980  return(false); // failed to find required element
12981 }
12982 
12983 // ---------------------------------------------------------------------------
12984 
12985 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
12986 /*
12987  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
12988  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
12989  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
12990  Keep a count of entries in SearchVector during the current function call, so that this number can be
12991  erased for an unproductive branch search.
12992  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
12993  element. If so save it & return true. If not check if buffer, continuation, or earlier position
12994  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
12995  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
12996  If not any of above, store element in searchvector, set the new current element values from the
12997  SearchElement, then go back to the while loop for the next step in the search.
12998 */
12999 {
13000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
13001  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
13002  int VectorCount = 0;
13003 
13004  while(true)
13005  {
13006  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
13007  {
13008  for(int x = 0; x < VectorCount; x++)
13009  {
13010  SearchVector.erase(SearchVector.end() - 1);
13011  }
13012  Utilities->CallLogPop(141);
13013  return(false);
13014  }
13015  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
13016  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
13017  TPrefDirElement SearchElement(NextTrackElement);
13018  SearchElement.TrackVectorPosition = NextPosition;
13019  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
13020  SearchElement.ELinkPos = NextELinkPos;
13021  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
13022  int NextXLinkPos;
13023  if(SearchElement.ELinkPos == 0)
13024  {
13025  NextXLinkPos = 1;
13026  }
13027  if(SearchElement.ELinkPos == 1)
13028  {
13029  NextXLinkPos = 0;
13030  }
13031  if(SearchElement.ELinkPos == 2)
13032  {
13033  NextXLinkPos = 3;
13034  }
13035  if(SearchElement.ELinkPos == 3)
13036  {
13037  NextXLinkPos = 2;
13038  }
13039  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
13040  {
13041  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
13042  // but may be buffers, continuation or gap
13043  SearchElement.XLinkPos = NextXLinkPos;
13044  }
13045 // can't set XLink or XLinkPos yet if the element is a leading point.
13046 // check if found it
13047  if(SearchElement.TrackVectorPosition == RequiredPosition)
13048  {
13049  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
13050  VectorCount++; // not really needed but include for tidyness
13051  TotalSearchCount++;
13052  Utilities->CallLogPop(142);
13053  return(true);
13054  }
13055 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
13056 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
13057 // at a time - drop this
13058 /*
13059  if(PrefDirVector.size() > 200)
13060  {
13061  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
13062  Utilities->CallLogPop(1419);
13063  return false;
13064  }
13065 */
13066 // check if a buffer or continuation
13067  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
13068  {
13069  for(int x = 0; x < VectorCount; x++)
13070  {
13071  SearchVector.erase(SearchVector.end() - 1);
13072  }
13073  Utilities->CallLogPop(143);
13074  return(false);
13075  }
13076 // check if reached an earlier position on search PrefDir with same entry value
13077  for(unsigned int x = 0; x < SearchVector.size(); x++)
13078  {
13079  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
13080  {
13081  for(int x = 0; x < VectorCount; x++)
13082  {
13083  SearchVector.erase(SearchVector.end() - 1);
13084  }
13085  Utilities->CallLogPop(144);
13086  return(false);
13087  }
13088  }
13089 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
13090 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
13091  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13092  {
13093  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
13094  {
13095  for(int x = 0; x < VectorCount; x++)
13096  {
13097  SearchVector.erase(SearchVector.end() - 1);
13098  }
13099  Utilities->CallLogPop(1417);
13100  return(false);
13101  }
13102  }
13103 
13104 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
13105 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
13106 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
13108  {
13109  for(int x = 0; x < VectorCount; x++)
13110  {
13111  SearchVector.erase(SearchVector.end() - 1);
13112  }
13113  Utilities->CallLogPop(1691);
13114  return(false);
13115  }
13116 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
13117  if(SearchVector.size() > 150)
13118  {
13119  for(int x = 0; x < VectorCount; x++)
13120  {
13121  SearchVector.erase(SearchVector.end() - 1);
13122  }
13123  Utilities->CallLogPop(1418);
13124  return(false);
13125  }
13126 // check if reached a leading point
13127  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
13128  {
13129 // push element with XLink set to position [1]
13130  SearchElement.XLink = SearchElement.Link[1];
13131  SearchElement.XLinkPos = 1;
13132  SearchVector.push_back(SearchElement);
13133  VectorCount++;
13134  TotalSearchCount++;
13135  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
13136  // Note that have to use a TTrackElement in the recursive search, so SearchElement
13137  // can't be used. NextTrackElement is the corresponding TTrackElement.
13138  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
13139  {
13140  Utilities->CallLogPop(145);
13141  return(true);
13142  }
13143  else
13144  {
13145 // remove leading point with XLinkPos [1]
13146  SearchVector.erase(SearchVector.end() - 1);
13147  VectorCount--;
13148 // push element with XLink set to position [3]
13149  SearchElement.XLink = SearchElement.Link[3];
13150  SearchElement.XLinkPos = 3;
13151  SearchVector.push_back(SearchElement);
13152  VectorCount++;
13153  TotalSearchCount++;
13154 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
13155  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
13156  {
13157  Utilities->CallLogPop(146);
13158  return(true);
13159  }
13160  else
13161  {
13162  for(int x = 0; x < VectorCount; x++)
13163  {
13164  SearchVector.erase(SearchVector.end() - 1);
13165  }
13166  Utilities->CallLogPop(147);
13167  return(false);
13168  }
13169  }
13170  } // if leading point
13171 
13172 // here if ordinary element, push it, inc vector & update CurrentTrackElement
13173 // ready for next element on PrefDir
13174  SearchVector.push_back(SearchElement);
13175  VectorCount++;
13176  TotalSearchCount++;
13177  XLinkPos = NextXLinkPos;
13178  CurrentTrackElement = SearchElement;
13179  } // while(true)
13180 }
13181 
13182 // ---------------------------------------------------------------------------
13183 
13185 /*
13186  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
13187  for each element on the search PrefDir, though if the last element is a leading point
13188  then the final XLink won't be set.
13189  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
13190  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
13191  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
13192 */
13193 {
13194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
13195  if(SearchVector.size() == 0)
13196  {
13197  throw Exception("Error, SearchVector empty");
13198  }
13199 // get first SearchElement in order to set last PrefDirelement
13200  TPrefDirElement SearchElement = SearchVector.at(0);
13201 
13202 // set last PrefDir element XLink & ELink values if not already set
13203 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
13204  for(int x = 0; x < 4; x++)
13205  {
13206  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
13207  {
13208  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
13209  {
13210  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
13211  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
13212  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
13213  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
13214  }
13215  int ELinkPos;
13216  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
13217  {
13218  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
13219  }
13220  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
13221  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
13222  {
13223  ELinkPos = 0;
13224  }
13225  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
13226  {
13227  ELinkPos = 3;
13228  }
13229  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
13230  {
13231  ELinkPos = 2;
13232  }
13233  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
13234  {
13235  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
13236  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
13237  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
13238  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
13239  }
13240  break; // no point going any further
13241  }
13242  }
13243 // set EXNumber for last PrefDir element, unless already set
13244 // won't be set if was first element or a leading point
13245  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
13246  {
13247 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
13248  int EXArray[32][2] = {
13249  {4,6},{2,8}, //horizontal & vertical
13250  {2,4},{6,2},{8,6},{4,8}, //sharp curves
13251  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
13252  {1,9},{3,7} //forward & reverse diagonals
13253 */
13254 
13255  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
13256  {
13257  throw Exception("Error in EntryExitNumber 1");
13258  }
13259  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
13260  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
13261  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
13262  }
13263 // Last PrefDir element now complete
13264 
13265 // construct remaining PrefDir elements from searchvector
13266  for(unsigned int x = 0; x < SearchVector.size(); x++)
13267  {
13268  SearchElement = SearchVector.at(x);
13269  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
13270  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
13271  PrefDirElement.ELink = SearchElement.ELink;
13272  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
13273  PrefDirElement.XLink = SearchElement.XLink;
13274  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
13275 // if XLink & XLinkPos not set don't account for them in CheckCount
13276  if(PrefDirElement.XLink == -1)
13277  {
13278  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13279  }
13280  // & TrackVectorPosition
13281  else
13282  {
13283  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
13284  }
13285  // XLink, XLinkPos, TrackVectorPosition
13286 
13287 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
13288  if(PrefDirElement.XLink != -1)
13289  {
13290  if(!(PrefDirElement.EntryExitNumber()))
13291  {
13292  throw Exception("Error in EntryExitNumber 2");
13293  }
13294  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
13295  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
13296  PrefDirElement.CheckCount++;
13297  // all values now incorporated if not a leading point
13298  }
13299 // store PrefDir element
13300  StorePrefDirElement(2, PrefDirElement);
13301  }
13302 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
13303  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
13304  {
13305  if(ValidatePrefDir(2))
13306  {
13307  ;
13308  } // error messages given within function
13309 
13310  }
13312 /* drop this, check dropped from search
13313  if(PrefDirVector.size() > 200)
13314  {
13315  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
13316  }
13317 */
13318  Utilities->CallLogPop(148);
13319 }
13320 
13321 // ---------------------------------------------------------------------------
13322 
13323 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
13324 /*
13325  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
13326  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
13327 */
13328 {
13329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
13330  LeadingPoints = false;
13331  if(PrefDirVector.empty())
13332  {
13333  Utilities->CallLogPop(1786);
13334  return(false); // should never be empty but allow for it for safety
13335  }
13336  if(PrefDirVector.size() == 1)
13337  {
13338  Utilities->CallLogPop(149);
13339  return(false); // can't end if only one element
13340  }
13341 /*
13342  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
13343  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
13344  {
13345  Utilities->CallLogPop(150);
13346  return true;
13347  }
13348 */
13349 // allow for anything but leading points
13350  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
13351  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
13352  {
13353  Utilities->CallLogPop(1776);
13354  return(true);
13355  }
13356  else
13357  {
13358  LeadingPoints = true;
13359  Utilities->CallLogPop(151);
13360  return(false);
13361  }
13362 }
13363 
13364 // ---------------------------------------------------------------------------
13365 
13367 /*
13368  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
13369  and that every element is connected to the next element
13370 */
13371 {
13372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
13373  int Position;
13374  AnsiString ErrorString;
13375  bool Error = false;
13376 
13377  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
13378  {
13379  if(PrefDirVector.at(x).HLoc == -2000000000)
13380  {
13381  Error = true;
13382  ErrorString = "HLoc";
13383  Position = x;
13384  }
13385  if(PrefDirVector.at(x).VLoc == -2000000000)
13386  {
13387  Error = true;
13388  ErrorString = "VLoc";
13389  Position = x;
13390  }
13391  if(PrefDirVector.at(x).ELink == -1)
13392  {
13393  Error = true;
13394  ErrorString = "ELink";
13395  Position = x;
13396  }
13397  if(PrefDirVector.at(x).ELinkPos == -1)
13398  {
13399  Error = true;
13400  ErrorString = "ELinkPos";
13401  Position = x;
13402  }
13403  if(PrefDirVector.at(x).XLink == -1)
13404  {
13405  Error = true;
13406  ErrorString = "XLink";
13407  Position = x;
13408  }
13409  if(PrefDirVector.at(x).XLinkPos == -1)
13410  {
13411  Error = true;
13412  ErrorString = "XLinkPos";
13413  Position = x;
13414  }
13415  if(PrefDirVector.at(x).SpeedTag == 0)
13416  {
13417  Error = true;
13418  ErrorString = "Tag";
13419  Position = x;
13420  }
13421  if(PrefDirVector.at(x).TrackVectorPosition == -1)
13422  {
13423  Error = true;
13424  ErrorString = "TrackVectorPosition";
13425  Position = x;
13426  }
13427  if(PrefDirVector.at(x).EXNumber == -1)
13428  {
13429  Error = true;
13430  ErrorString = "EXNumber";
13431  Position = x;
13432  }
13433  if(PrefDirVector.at(x).CheckCount != 9)
13434  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
13435  {
13436  Error = true;
13437  ErrorString = "CheckCount";
13438  Position = x;
13439  }
13440 // extra checks
13441  if(PrefDirVector.at(x).EXGraphicPtr == 0)
13442  {
13443  Error = true;
13444  ErrorString = "EntryGraphicPtr";
13445  Position = x;
13446  }
13447  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
13448  {
13449  Error = true;
13450  ErrorString = "EntryDirectionGraphicPtr";
13451  Position = x;
13452  }
13453 // end of extra checks
13454  if(x > 0)
13455  {
13456  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
13457  {
13458  Error = true;
13459  ErrorString = "Last XLink not connected to this element";
13460  Position = x;
13461  }
13462  }
13463  }
13464  if(Error)
13465  {
13466  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
13467  }
13468  else
13469  {
13470  Utilities->CallLogPop(153);
13471  return(true);
13472  }
13473 }
13474 
13475 // ---------------------------------------------------------------------------
13476 
13477 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
13478 /*
13479  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
13480  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
13481  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
13482  or a leading point.
13483 */
13484 {
13485  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13486  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
13487  {
13488  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
13489  {
13490  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
13491  {
13492  ErasePrefDirElementAt(1, PrefDirVecPos);
13493  }
13494  if(PrefDirVector.size() == 0)
13495  {
13496  Utilities->CallLogPop(154);
13497  return(true);
13498  }
13499  if(PrefDirVector.size() == 1)
13500  {
13501  PrefDirVector.at(x - 1).ELinkPos = -1;
13502  PrefDirVector.at(x - 1).ELink = -1;
13503  PrefDirVector.at(x - 1).XLinkPos = -1;
13504  PrefDirVector.at(x - 1).XLink = -1;
13505  PrefDirVector.at(x - 1).EXNumber = -1;
13506  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13507  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13508  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
13509  Utilities->CallLogPop(155);
13510  return(true);
13511  }
13512  // here with truncate element not first element, so ELink & ELinkPos set
13513  // unset XLink & Pos if a leading point
13514  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
13515  {
13516  PrefDirVector.at(x - 1).XLinkPos = -1;
13517  PrefDirVector.at(x - 1).XLink = -1;
13518  PrefDirVector.at(x - 1).EXNumber = -1;
13519  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
13520  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
13521  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
13522  Utilities->CallLogPop(156);
13523  return(true);
13524  }
13525  Utilities->CallLogPop(157);
13526  return(true);
13527  }
13528  }
13529  Utilities->CallLogPop(158);
13530  return(false);
13531 }
13532 
13533 // ---------------------------------------------------------------------------
13534 
13535 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
13536 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
13537 /*
13538  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
13539  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
13540  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
13541  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
13542  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
13543  displayed.
13544 */
13545 {
13546  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
13547  AnsiString((short)BuildingPrefDir));
13548  int HPos, VPos;
13549 
13550  if(PrefDirSize() == 0)
13551  {
13552  Utilities->CallLogPop(159);
13553  return;
13554  }
13555  for(unsigned int x = 0; x < PrefDirSize(); x++)
13556  {
13557  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
13558 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
13559 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
13560 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
13561  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
13562  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
13563  // only the front half of which will be overplotted by the back of the train, then when the train is
13564  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
13565  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
13566  {
13567  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
13568  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
13569  {
13570  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13571  }
13572  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
13573  // Route, no direction if a single element
13574  {
13575  if(x == 0)
13576  {
13577  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13578  }
13579  if(x == (PrefDirSize() - 1))
13580  {
13581  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
13582  }
13583  }
13584  }
13585  }
13586 
13587 // set start & end element colours if building a PrefDir
13588  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
13589  {
13590  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
13591  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
13592  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
13593  // set last element colour
13594  if(PrefDirSize() > 1)
13595  {
13596  unsigned int LatestPos = PrefDirSize() - 1;
13597  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
13598  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
13599  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
13600  }
13601  }
13602  Disp->Update();
13603  Utilities->CallLogPop(160);
13604 }
13605 
13606 // ---------------------------------------------------------------------------
13607 
13609 /*
13610  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
13611  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
13612 */
13613 {
13614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
13615  if(PrefDirSize() == 0)
13616  {
13617  Utilities->CallLogPop(1547);
13618  return;
13619  }
13620  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13621  bool FoundFlag;
13623  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13624 
13625  while(MMIT != PrefDir4MultiMap.end())
13626  {
13627  H = MMIT->first.first;
13628  V = MMIT->first.second;
13629  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13630  // always found in order, any missing have PrefDirPosx == -1
13631  if(PrefDirPos0 > -1)
13632  {
13633  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13634  }
13635  if(PrefDirPos1 > -1)
13636  {
13637  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
13638  }
13639  if(PrefDirPos2 > -1)
13640  {
13641  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
13642  }
13643  if(PrefDirPos3 > -1)
13644  {
13645  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
13646  }
13647  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13648  {
13649  // need to plot all 4 in order to obtain all the direction graphics
13650  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13651  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13652  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13653  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13654  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13655  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13656  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13657  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13658  MMIT++;
13659  MMIT++;
13660  MMIT++;
13661  MMIT++;
13662  }
13663  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13664  {
13665  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13666  {
13667  // 0 & 1 constitute the bidirectional PrefDir
13668  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13669  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13670  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13671  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13672  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13673  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13674  MMIT++;
13675  MMIT++;
13676  MMIT++;
13677  }
13678  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13679  {
13680  // 0 & 2 constitute the bidirectional PrefDir
13681  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13682  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13683  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13684  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13685  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13686  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13687  MMIT++;
13688  MMIT++;
13689  MMIT++;
13690  }
13691  else
13692  {
13693  // 1 & 2 constitute the bidirectional PrefDir
13694  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13695  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13696  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13697  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13698  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13699  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13700  MMIT++;
13701  MMIT++;
13702  MMIT++;
13703  }
13704  }
13705  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13706  {
13707  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13708  {
13709  // 0 & 1 constitute the bidirectional PrefDir
13710  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13711  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13712  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13713  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13714  MMIT++;
13715  MMIT++;
13716  }
13717  else
13718  {
13719  // 2 unidirectional PrefDirs
13720  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13721  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13722  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13723  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13724  MMIT++;
13725  MMIT++;
13726  }
13727  }
13728  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13729  {
13730  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13731  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13732  MMIT++;
13733  }
13734  }
13735  Disp->Update();
13736  Utilities->CallLogPop(1548);
13737 }
13738 
13739 // ---------------------------------------------------------------------------
13740 
13741 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
13742 {
13743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
13744  int TempInt;
13745 
13746  ClearPrefDir();
13747  int NumberOfPrefDirElements = 0;
13748 
13749  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13750  for(int x = 0; x < NumberOfPrefDirElements; x++)
13751  {
13752  VecFile >> TempInt; // TrackVectorPosition
13753  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
13754  LoadPrefDirElement.TrackVectorPosition = TempInt;
13755  VecFile >> TempInt;
13756  LoadPrefDirElement.ELink = TempInt;
13757  VecFile >> TempInt;
13758  LoadPrefDirElement.ELinkPos = TempInt;
13759  VecFile >> TempInt;
13760  LoadPrefDirElement.XLink = TempInt;
13761  VecFile >> TempInt;
13762  LoadPrefDirElement.XLinkPos = TempInt;
13763  VecFile >> TempInt;
13764  LoadPrefDirElement.EXNumber = TempInt;
13765  VecFile >> TempInt;
13766  LoadPrefDirElement.CheckCount = TempInt;
13767  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13768  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13769  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13770  if(!(LoadPrefDirElement.IsARoute))
13771  {
13772  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13773  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13774  }
13775  else
13776  {
13777  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13778  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13779  LoadPrefDirElement.PrefDirRoute);
13780  }
13781  StorePrefDirElement(5, LoadPrefDirElement);
13782  Utilities->LoadFileString(VecFile); // marker
13783  }
13785  Utilities->CallLogPop(161);
13786 }
13787 
13788 // ---------------------------------------------------------------------------
13789 
13790 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
13791 {
13792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
13793  int TempInt;
13794 
13795  ClearPrefDir();
13796  int NumberOfPrefDirElements = 0;
13797 
13798  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13799  for(int x = 0; x < NumberOfPrefDirElements; x++)
13800  {
13801  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
13802  VecFile >> TempInt; // TrackVectorPosition
13803  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
13804  LoadPrefDirElement.TrackVectorPosition = TempInt;
13805  VecFile >> TempInt;
13806  LoadPrefDirElement.ELink = TempInt;
13807  VecFile >> TempInt;
13808  LoadPrefDirElement.ELinkPos = TempInt;
13809  VecFile >> TempInt;
13810  LoadPrefDirElement.XLink = TempInt;
13811  VecFile >> TempInt;
13812  LoadPrefDirElement.XLinkPos = TempInt;
13813  VecFile >> TempInt;
13814  LoadPrefDirElement.EXNumber = TempInt;
13815  VecFile >> TempInt;
13816  LoadPrefDirElement.CheckCount = TempInt;
13817  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
13818  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
13819  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
13820  if(!(LoadPrefDirElement.IsARoute))
13821  {
13822  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
13823  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
13824  }
13825  else
13826  {
13827  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
13828  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
13829  LoadPrefDirElement.PrefDirRoute);
13830  }
13831  StorePrefDirElement(0, LoadPrefDirElement);
13832  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
13833  }
13835  Utilities->CallLogPop(1509);
13836 }
13837 
13838 // ---------------------------------------------------------------------------
13839 
13840 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
13841 /*
13842  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
13843  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
13844 */
13845 {
13846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
13847  int TempInt;
13848  int NumberOfPrefDirElements = 0;
13849 
13850  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
13851  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
13852  {
13853  Utilities->CallLogPop(1152);
13854  return(false);
13855  }
13856  for(int x = 0; x < NumberOfPrefDirElements; x++)
13857  {
13858  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
13859  {
13860  Utilities->CallLogPop(1766);
13861  return(false);
13862  }
13863  VecFile >> TempInt;
13864  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
13865  {
13866  Utilities->CallLogPop(163);
13867  return(false);
13868  }
13869  VecFile >> TempInt;
13870  if((TempInt < -1) || (TempInt > 9)) // ELink
13871  {
13872  Utilities->CallLogPop(162);
13873  return(false);
13874  }
13875  VecFile >> TempInt;
13876  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
13877  {
13878  Utilities->CallLogPop(164);
13879  return(false);
13880  }
13881  VecFile >> TempInt;
13882  if((TempInt < -1) || (TempInt > 9)) // XLink
13883  {
13884  Utilities->CallLogPop(165);
13885  return(false);
13886  }
13887  VecFile >> TempInt;
13888  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
13889  {
13890  Utilities->CallLogPop(166);
13891  return(false);
13892  }
13893  VecFile >> TempInt;
13894  if((TempInt < -1) || (TempInt > 27)) // EXNumber
13895  {
13896  Utilities->CallLogPop(167);
13897  return(false);
13898  }
13899  VecFile >> TempInt;
13900  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
13901  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
13902  // ELinkPos, XLink, XLinkPos & EXNumber
13903  {
13904  Utilities->CallLogPop(168);
13905  return(false);
13906  }
13907  VecFile >> TempInt;
13908  if((TempInt != 0) && (TempInt != 1)) // RouteElement
13909  {
13910  Utilities->CallLogPop(1147);
13911  return(false);
13912  }
13913  VecFile >> TempInt;
13914  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
13915  {
13916  Utilities->CallLogPop(1510);
13917  return(false);
13918  }
13919  VecFile >> TempInt;
13920  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
13921  {
13922  Utilities->CallLogPop(1148);
13923  return(false);
13924  }
13925  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
13926  {
13927  Utilities->CallLogPop(1700);
13928  return(false);
13929  }
13930  }
13931  Utilities->CallLogPop(169);
13932  return(true);
13933 }
13934 
13935 // ---------------------------------------------------------------------------
13936 
13937 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
13938 {
13939  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
13940  int NumberOfPrefDirElements = PrefDirVector.size();
13941 
13942  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
13943  for(int y = 0; y < NumberOfPrefDirElements; y++)
13944  {
13945  VecFile << y << '\n'; // extra
13946  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
13947  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
13948  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
13949  VecFile << PrefDirVector.at(y).XLink << '\n';
13950  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
13951  VecFile << PrefDirVector.at(y).EXNumber << '\n';
13952  VecFile << PrefDirVector.at(y).CheckCount << '\n';
13953  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
13954  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
13955  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
13956  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
13957  {
13958  VecFile << "************" << '\0' << '\n'; // marker
13959  }
13960  else
13961  {
13962  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13963  }
13964  }
13965  Utilities->CallLogPop(170);
13966 }
13967 
13968 // ---------------------------------------------------------------------------
13969 
13970 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
13971 {
13972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
13973  int NumberOfSearchElements = SearchVector.size();
13974 
13975  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
13976  for(int y = 0; y < NumberOfSearchElements; y++)
13977  {
13978  VecFile << y << '\n'; // extra
13979  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
13980  VecFile << SearchVector.at(y).ELink << '\n';
13981  VecFile << SearchVector.at(y).ELinkPos << '\n';
13982  VecFile << SearchVector.at(y).XLink << '\n';
13983  VecFile << SearchVector.at(y).XLinkPos << '\n';
13984  VecFile << SearchVector.at(y).EXNumber << '\n';
13985  VecFile << SearchVector.at(y).CheckCount << '\n';
13986  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
13987  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
13988  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
13989  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
13990  {
13991  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13992  }
13993  else
13994  {
13995  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
13996  }
13997  }
13998  Utilities->CallLogPop(1847);
13999 }
14000 
14001 // ---------------------------------------------------------------------------
14002 
14003 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
14004 /*
14005  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
14006  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
14007 */
14008 {
14009  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
14010  AnsiString(VLoc));
14011  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
14012 
14013  if(VecPos > -1)
14014  {
14015  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
14016  }
14017  else
14018  {
14019  Utilities->CallLogPop(171);
14020  return;
14021  }
14022  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
14023  if(VecPos > -1)
14024  {
14025  ErasePrefDirElementAt(3, VecPos);
14026  }
14027  else
14028  {
14029  Utilities->CallLogPop(172);
14030  return;
14031  }
14032  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
14033  if(VecPos > -1)
14034  {
14035  ErasePrefDirElementAt(4, VecPos);
14036  }
14037  else
14038  {
14039  Utilities->CallLogPop(173);
14040  return;
14041  }
14042  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
14043  if(VecPos > -1)
14044  {
14045  ErasePrefDirElementAt(5, VecPos);
14046  }
14047  else
14048  {
14049  Utilities->CallLogPop(174);
14050  return;
14051  }
14052  Utilities->CallLogPop(175);
14053 }
14054 
14055 // ---------------------------------------------------------------------------
14056 /*
14057  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
14058  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
14059 
14060  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
14061  in their place so that existing linkages will be preserved. At this stage this function is called to remove
14062  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
14063  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
14064  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
14065  PrefDirVector to correspond to the new track layout.
14066 
14067  {
14068  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
14069  if(PrefDirSize() == 0)
14070  {
14071  Utilities->CallLogPop(176);
14072  return;
14073  }
14074  for(int x=(PrefDirVector.size()-1);x>=0;x--)
14075  {
14076  int TV = PrefDirVector.at(x).TrackVectorPosition;
14077  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
14078  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
14079  if(Track->BlankElementAt(0, TV))
14080  {
14081  ErasePrefDirElementAt(6, x);
14082  }
14083  //if was a blankelement at x then ConnELink and ConnXLink both -1
14084  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
14085  {
14086  ErasePrefDirElementAt(7, x);
14087  }
14088  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
14089  //needs to be erased once, but if don't use 'else' then will erase two elements
14090  //since 'x' will correspond to the element after the first erased element
14091  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
14092  {
14093  ErasePrefDirElementAt(8, x);
14094  }
14095  }
14096  Utilities->CallLogPop(177);
14097  }
14098 */
14099 // ---------------------------------------------------------------------------
14100 
14101 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
14102 /*
14103  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
14104  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
14105 */
14106 {
14107  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
14108  bool AlreadyPresent, FoundFlag;
14109  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14110 
14111  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
14112  {
14113  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
14114  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14115  AlreadyPresent = false;
14116  if(FoundFlag)
14117  {
14118  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
14119  {
14120  AlreadyPresent = true;
14121  }
14122  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
14123  {
14124  AlreadyPresent = true;
14125  }
14126  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
14127  {
14128  AlreadyPresent = true;
14129  }
14130  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
14131  {
14132  AlreadyPresent = true;
14133  }
14134  }
14135  if(!AlreadyPresent)
14136  {
14137  StorePrefDirElement(4, TempElement);
14138  }
14139  }
14141  Utilities->CallLogPop(178);
14142 }
14143 /* earlier brute force search
14144  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
14145  {
14146  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
14147  bool AlreadyPresent = false;
14148  for(unsigned int y = 0;y<PrefDirSize();y++)
14149  {
14150  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
14151  }
14152  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
14153  }
14154 */
14155 
14156 // ---------------------------------------------------------------------------
14157 
14159 /*
14160  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
14161  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
14162  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
14163  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
14164  positions are likely to have changed, so this function is called to reset all the necessary connections and
14165  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
14166  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
14167  shouldn't have changed.
14168 */
14169 {
14170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
14171  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14172  {
14173  bool FoundFlag;
14174  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14175  if(FoundFlag)
14176  {
14177  PrefDirVector.at(x).TrackVectorPosition = VecPos;
14178  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
14179  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
14180  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
14181  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
14182  for(unsigned int z = 0; z < 4; z++)
14183  {
14184  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
14185  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
14186  }
14187  }
14188  else
14189  {
14190  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
14191  }
14192  }
14193  Utilities->CallLogPop(179);
14194 }
14195 
14196 // ---------------------------------------------------------------------------
14197 
14199 /*
14200  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
14201 */
14202 {
14203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
14204  bool DiscrepancyFound = false;
14205 
14206  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14207  {
14208  bool FoundFlag;
14209  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14210  if(FoundFlag)
14211  {
14212  TPrefDirElement PE = PrefDirVector.at(x);
14213  if(PE.TrackVectorPosition != VecPos)
14214  {
14215  DiscrepancyFound = true;
14216  break;
14217  }
14218  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14219  {
14220  DiscrepancyFound = true;
14221  break;
14222  }
14223  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14224  {
14225  DiscrepancyFound = true;
14226  break;
14227  }
14228  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
14229  {
14230  DiscrepancyFound = true;
14231  break;
14232  }
14233  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
14234  {
14235  DiscrepancyFound = true;
14236  break;
14237  }
14238  }
14239  else
14240  {
14241  DiscrepancyFound = true;
14242  }
14243  }
14244  if(DiscrepancyFound)
14245  {
14246  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
14247  ClearPrefDir(); // also clears multimap
14248  }
14249  Utilities->CallLogPop(1436);
14250 }
14251 
14252 // ---------------------------------------------------------------------------
14253 
14255 /*
14256  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
14257  return true for OK
14258 */
14259 {
14260  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
14261  bool DiscrepancyFound = false;
14262 
14263  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
14264  {
14265  bool FoundFlag;
14266  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
14267  if(FoundFlag)
14268  {
14269  TPrefDirElement PE = PrefDirVector.at(x);
14270  if(PE.TrackVectorPosition != VecPos)
14271  {
14272  DiscrepancyFound = true;
14273  }
14274  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
14275  {
14276  DiscrepancyFound = true;
14277  break;
14278  }
14279  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
14280  {
14281  DiscrepancyFound = true;
14282  break;
14283  }
14284  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
14285  {
14286  DiscrepancyFound = true;
14287  break;
14288  }
14289  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
14290  {
14291  DiscrepancyFound = true;
14292  break;
14293  }
14294  }
14295  else
14296  {
14297  DiscrepancyFound = true;
14298  }
14299  }
14300  Utilities->CallLogPop(1512);
14301  return(!DiscrepancyFound);
14302 }
14303 
14304 // ---------------------------------------------------------------------------
14305 
14306 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
14307 /*
14308  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
14309  turn and for the overall sizes.
14310 */
14311 {
14312  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
14313  bool FoundFlag = false;
14314  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
14315 
14316  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
14317  {
14318  TPrefDirElement CheckElement = PrefDirVector.at(a);
14319  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
14320  if(!FoundFlag)
14321  {
14322  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
14323  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
14324  }
14325  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
14326  {
14327  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
14328  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
14329  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
14330  }
14331  }
14332  if(PrefDirVector.size() != PrefDir4MultiMap.size())
14333  {
14334  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
14335  + " Caller=" + (AnsiString)Caller);
14336  }
14337  Utilities->CallLogPop(180);
14338 }
14339 
14340 // ---------------------------------------------------------------------------
14341 
14342 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
14343  int &PrefDirPos3)
14344 /*
14345  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
14346  two tracks for 4-entry elements. This function retrieves all elements that are present at a given H & V
14347  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
14348  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
14349  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
14350 */
14351 {
14352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
14353  AnsiString(VLoc));
14354  THVPair PrefDirMapKeyPair;
14355 
14356  PrefDirPos0 = -1;
14357  PrefDirPos1 = -1;
14358  PrefDirPos2 = -1;
14359  PrefDirPos3 = -1;
14360  FoundFlag = false;
14361  PrefDirMapKeyPair.first = HLoc;
14362  PrefDirMapKeyPair.second = VLoc;
14363  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14364 
14365  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
14366  if(ItPair.first == ItPair.second) //none found
14367  {
14368  Utilities->CallLogPop(181);
14369  return;
14370  }
14371  else
14372  {
14373  FoundFlag = true;
14374  PrefDirPos0 = ItPair.first->second;
14375  ItPair.first++;
14376  if(ItPair.first == ItPair.second)
14377  {
14378  Utilities->CallLogPop(182); //only one found
14379  return;
14380  }
14381  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14382  {
14383  PrefDirPos1 = ItPair.first->second;
14384  }
14385  ItPair.first++;
14386  if(ItPair.first == ItPair.second)
14387  {
14388  Utilities->CallLogPop(183); //2 found
14389  return;
14390  }
14391  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14392  {
14393  PrefDirPos2 = ItPair.first->second;
14394  }
14395  ItPair.first++;
14396  if(ItPair.first == ItPair.second)
14397  {
14398  Utilities->CallLogPop(184); //3 found
14399  return;
14400  }
14401  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
14402  {
14403  PrefDirPos3 = ItPair.first->second; //4 found
14404  }
14405  }
14406  Utilities->CallLogPop(185);
14407 }
14408 
14409 // ---------------------------------------------------------------------------
14410 
14411 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14412 { //not used after modified the pref dir checking function at v2.13.0
14413  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
14414  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14415  try
14416  {
14417  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
14418  + "," + AnsiString(LinkNumberPos));
14419  bool FoundFlag;
14420  int PD0, PD1, PD2, PD3;
14421  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14422  {
14423  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14424  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14425  PD0, PD1, PD2, PD3);
14426  if(!FoundFlag)
14427  {
14428  Utilities->CallLogPop(2282);
14429  return(false);
14430  }
14431  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14432  {
14433  if(PD0 > -1)
14434  {
14435  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
14436  {
14437  LinkedPrefDirVectorNumber = PD0;
14438  Utilities->CallLogPop(2283);
14439  return(true);
14440  }
14441  }
14442  if(PD1 > -1)
14443  {
14444  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
14445  {
14446  LinkedPrefDirVectorNumber = PD1;
14447  Utilities->CallLogPop(2284);
14448  return(true);
14449  }
14450  }
14451  }
14452  if(PD0 > -1)
14453  {
14454  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
14455  {
14456  LinkedPrefDirVectorNumber = PD0;
14457  Utilities->CallLogPop(2285);
14458  return(true);
14459  }
14460  }
14461  if(PD1 > -1)
14462  {
14463  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
14464  {
14465  LinkedPrefDirVectorNumber = PD1;
14466  Utilities->CallLogPop(2286);
14467  return(true);
14468  }
14469  }
14470  if(PD2 > -1)
14471  {
14472  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
14473  {
14474  LinkedPrefDirVectorNumber = PD2;
14475  Utilities->CallLogPop(2287);
14476  return(true);
14477  }
14478  }
14479  if(PD3 > -1)
14480  {
14481  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
14482  {
14483  LinkedPrefDirVectorNumber = PD3;
14484  Utilities->CallLogPop(2288);
14485  return(true);
14486  }
14487  }
14488  LinkedPrefDirVectorNumber = -1;
14489  Utilities->CallLogPop(2289);
14490  return(false);
14491  }
14492  else //buffer or continuation, no link at position 0 but not a failure
14493  {
14494  LinkedPrefDirVectorNumber = -1;
14495  Utilities->CallLogPop(2290);
14496  return(true);
14497  }
14498  }
14499  catch(const Exception &e) //non error catch
14500  {
14501  LinkedPrefDirVectorNumber = -1;
14502  Utilities->CallLogPop(2291);
14503  return(false);
14504  }
14505 }
14506 
14507 // ---------------------------------------------------------------------------
14508 
14509 bool TOnePrefDir::FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
14510 { //not used after modified the pref dir checking function at v2.13.0
14511  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if finds same direction pref dir with linked
14512  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
14513  try
14514  {
14515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingCompatiblePrefDir," + AnsiString(PrefDirVectorNumber)
14516  + "," + AnsiString(LinkNumberPos));
14517  bool FoundFlag;
14518  int PD0, PD1, PD2, PD3;
14519  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
14520  {
14521  GetVectorPositionsFromPrefDir4MultiMap(31, Track->TrackElementAt(1463, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
14522  Track->TrackElementAt(1464, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
14523  PD0, PD1, PD2, PD3);
14524  if(!FoundFlag)
14525  {
14526  Utilities->CallLogPop(2468);
14527  return(false);
14528  }
14529  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
14530  { //only PD0 or 1 will be set, else have track linking error that will be found earlier
14531  if(PD0 > -1)
14532  {
14533  if((PrefDirVector.at(PD0).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD0).XLink))
14534  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD0).ELink))))
14535  {
14536  LinkedPrefDirVectorNumber = PD0;
14537  Utilities->CallLogPop(2469);
14538  return(true);
14539  }
14540  }
14541  if(PD1 > -1)
14542  {
14543  if((PrefDirVector.at(PD1).TrackType == GapJump) && ((PrefDirVector.at(PrefDirVectorNumber).ELink == (10 - PrefDirVector.at(PD1).XLink))
14544  || (PrefDirVector.at(PrefDirVectorNumber).XLink == (10 - PrefDirVector.at(PD1).ELink))))
14545  {
14546  LinkedPrefDirVectorNumber = PD1;
14547  Utilities->CallLogPop(2470);
14548  return(true);
14549  }
14550  }
14551  LinkedPrefDirVectorNumber = -1;
14552  Utilities->CallLogPop(2471);
14553  return(false);
14554  }
14555  if(PD0 > -1)
14556  {
14557  if((PrefDirVector.at(PD0).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD0).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14558  {
14559  LinkedPrefDirVectorNumber = PD0;
14560  Utilities->CallLogPop(2472);
14561  return(true);
14562  }
14563  }
14564  if(PD1 > -1)
14565  {
14566  if((PrefDirVector.at(PD1).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD1).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14567  {
14568  LinkedPrefDirVectorNumber = PD1;
14569  Utilities->CallLogPop(2473);
14570  return(true);
14571  }
14572  }
14573  if(PD2 > -1)
14574  {
14575  if((PrefDirVector.at(PD2).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD2).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14576  {
14577  LinkedPrefDirVectorNumber = PD2;
14578  Utilities->CallLogPop(2474);
14579  return(true);
14580  }
14581  }
14582  if(PD3 > -1)
14583  {
14584  if((PrefDirVector.at(PD3).ELink == (10 - PrefDirVector.at(PrefDirVectorNumber).XLink)) || (PrefDirVector.at(PD3).XLink == (10 - PrefDirVector.at(PrefDirVectorNumber).ELink)))
14585  {
14586  LinkedPrefDirVectorNumber = PD3;
14587  Utilities->CallLogPop(2475);
14588  return(true);
14589  }
14590  }
14591  LinkedPrefDirVectorNumber = -1;
14592  Utilities->CallLogPop(2476);
14593  return(false);
14594  }
14595  else //buffer or continuation, no link at position 0 but not a failure
14596  {
14597  LinkedPrefDirVectorNumber = -1;
14598  Utilities->CallLogPop(2477);
14599  return(true);
14600  }
14601  }
14602  catch(const Exception &e) //non error catch
14603  {
14604  LinkedPrefDirVectorNumber = -1;
14605  Utilities->CallLogPop(2478);
14606  return(false);
14607  }
14608 }
14609 
14610 // ---------------------------------------------------------------------------
14611 
14613 {
14614  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
14615  bool FoundFlag; //not used
14616  int PD0, PD1, PD2, PD3;
14617  //recover all PDs at the H & V of PDPtr
14618  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
14619 
14620  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
14621  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
14622 
14623  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
14624  {
14625  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
14626  {
14627  Utilities->CallLogPop(2292);
14628  return(true);
14629  }
14630  }
14631  if(PD1 > -1)
14632  {
14633  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
14634  {
14635  Utilities->CallLogPop(2293);
14636  return(true);
14637  }
14638  }
14639  if(PD2 > -1)
14640  {
14641  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
14642  {
14643  Utilities->CallLogPop(2294);
14644  return(true);
14645  }
14646  }
14647  if(PD3 > -1)
14648  {
14649  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
14650  {
14651  Utilities->CallLogPop(2295);
14652  return(true);
14653  }
14654  }
14655  Utilities->CallLogPop(2296);
14656  return(false);
14657 }
14658 
14659 // ---------------------------------------------------------------------------
14660 
14661 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
14662 /*
14663  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
14664 */
14665 {
14666  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
14667  PrefDirVector.push_back(LoadPrefDirElement);
14668  THVPair PrefDir4MultiMapKeyPair;
14669  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
14670 
14671  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
14672  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
14673  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
14674  PrefDir4MultiMapEntry.second = LastElementNumber(68);
14675  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
14676 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
14677  Utilities->CallLogPop(186);
14678 }
14679 
14680 // ---------------------------------------------------------------------------
14681 
14682 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
14683 /*
14684  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
14685  4MultiMap if they are greater than the erased value.
14686 */
14687 {
14688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
14689  bool FoundFlag;
14690 
14691  if(!PrefDirVector.empty())
14692  {
14693  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
14694  if(!FoundFlag)
14695  {
14696  throw Exception("Failed to find PrefDir4MultiMap erase element");
14697  }
14698  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
14699  PrefDir4MultiMap.erase(EraseIt);
14700  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
14702  }
14703  Utilities->CallLogPop(187);
14704 }
14705 
14706 // ---------------------------------------------------------------------------
14707 
14708 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
14709 /*
14710  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
14711  4MultiMap if they are greater than the erased value.
14712 */
14713 {
14714  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
14715  AnsiString(ErasedElementNumber));
14716  if(!PrefDir4MultiMap.empty())
14717  {
14718  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
14719  {
14720  if(MapPtr->second > ErasedElementNumber)
14721  {
14722  MapPtr->second--;
14723  }
14724  }
14725  }
14726  Utilities->CallLogPop(1450);
14727 }
14728 
14729 // ---------------------------------------------------------------------------
14730 
14731 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
14732 /*
14733  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
14734  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
14735  nothing is found this is an error but the error message is given in the calling function.
14736 */
14737 {
14738  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
14739  FoundFlag = false;
14740  if(PrefDirVectorPosition >= PrefDirVector.size())
14741  {
14742  throw Exception("PrefDirVectorPosition out of range");
14743  }
14744  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
14745  THVPair PrefDir4MultiMapKeyPair;
14746 
14747  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
14748  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
14749  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14750 
14751  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14752  if(ItPair.first == ItPair.second)
14753  {
14754  Utilities->CallLogPop(188);
14755  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
14756  }
14757  else
14758  {
14759  if(ItPair.first->second == PrefDirVectorPosition)
14760  {
14761  FoundFlag = true;
14762  Utilities->CallLogPop(189);
14763  return(ItPair.first);
14764  }
14765  ItPair.first++;
14766  if(ItPair.first == ItPair.second)
14767  {
14768  Utilities->CallLogPop(190);
14769  return(ItPair.first); // nothing found
14770  }
14771  if(ItPair.first->second == PrefDirVectorPosition)
14772  {
14773  FoundFlag = true;
14774  Utilities->CallLogPop(191);
14775  return(ItPair.first);
14776  }
14777  ItPair.first++;
14778  if(ItPair.first == ItPair.second)
14779  {
14780  Utilities->CallLogPop(192);
14781  return(ItPair.first); // nothing found
14782  }
14783  if(ItPair.first->second == PrefDirVectorPosition)
14784  {
14785  FoundFlag = true;
14786  Utilities->CallLogPop(193);
14787  return(ItPair.first);
14788  }
14789  ItPair.first++;
14790  if(ItPair.first == ItPair.second)
14791  {
14792  Utilities->CallLogPop(194);
14793  return(ItPair.first); // nothing found
14794  }
14795  if(ItPair.first->second == PrefDirVectorPosition)
14796  {
14797  FoundFlag = true;
14798  Utilities->CallLogPop(195);
14799  return(ItPair.first);
14800  }
14801  }
14802  Utilities->CallLogPop(196);
14803  return(ItPair.first); // nothing found
14804 }
14805 
14806 // ---------------------------------------------------------------------------
14807 
14808 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
14809 /*
14810  Although there may be up to four entries at one H & V position this function gets just one. It is
14811  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
14812  at H & V.
14813 */
14814 {
14815  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
14816  THVPair PrefDir4MultiMapKeyPair;
14817 
14818  PrefDir4MultiMapKeyPair.first = HLoc;
14819  PrefDir4MultiMapKeyPair.second = VLoc;
14820  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
14821 
14822  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
14823  if(ItPair.first == ItPair.second) // nothing found
14824  {
14825  Utilities->CallLogPop(197);
14826  return(-1);
14827  }
14828  else
14829  {
14830  Utilities->CallLogPop(198);
14831  return(ItPair.first->second);
14832  }
14833 }
14834 
14835 // ---------------------------------------------------------------------------
14836 
14837 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
14838 {
14839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
14840  bool ErasedFlag = false;
14841 
14842  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
14843  {
14844  if(PrefDirSize() == 0)
14845  {
14846  Utilities->CallLogPop(1511);
14847  return;
14848  }
14849  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
14850  {
14851  ErasedFlag = false;
14852  // use 'else' to ensure don't try to access an erased element
14853  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
14854  {
14855  ErasePrefDirElementAt(11, x);
14856  ErasedFlag = true;
14857  }
14858  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
14859  {
14860  ErasePrefDirElementAt(12, x);
14861  ErasedFlag = true;
14862  }
14863  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
14864  {
14865  ErasePrefDirElementAt(13, x);
14866  ErasedFlag = true;
14867  }
14868  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
14869  {
14870  ErasePrefDirElementAt(9, x);
14871  ErasedFlag = true;
14872  }
14873  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
14874  {
14875  ErasePrefDirElementAt(10, x);
14876  ErasedFlag = true;
14877  }
14878  if(!ErasedFlag)
14879  {
14880  // don't use 'else' here as may be more than one that need decrementing
14881  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
14882  {
14883  PrefDirVector.at(x).TrackVectorPosition--;
14884  }
14885  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
14886  {
14887  PrefDirVector.at(x).Conn[0]--;
14888  }
14889  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
14890  {
14891  PrefDirVector.at(x).Conn[1]--;
14892  }
14893  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
14894  {
14895  PrefDirVector.at(x).Conn[2]--;
14896  }
14897  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
14898  {
14899  PrefDirVector.at(x).Conn[3]--;
14900  }
14901  }
14902  }
14903  }
14904  Utilities->CallLogPop(1434);
14905 }
14906 
14907 // ---------------------------------------------------------------------------
14908 
14909 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
14910 {
14911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
14912  OverallDistance = 0;
14913  OverallSpeedLimit = 0;
14914  LeadingPointsAtLastElement = false;
14915  if(PrefDirSize() == 0) // shouldn't be empty when this called
14916  {
14917  Utilities->CallLogPop(1491);
14918  return;
14919  }
14920  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
14921  {
14922  LeadingPointsAtLastElement = true;
14923  Utilities->CallLogPop(1492);
14924  return;
14925  }
14926  for(unsigned int x = 0; x < PrefDirSize(); x++)
14927  {
14928  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
14929  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
14930  {
14931  OverallDistance += PrefDirElement.Length23;
14932  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14933  {
14934  if(x == 0)
14935  {
14936  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
14937  }
14938  else
14939  {
14940  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
14941  {
14942  OverallSpeedLimit = -1;
14943  }
14944  }
14945  }
14946  }
14947  else
14948  {
14949  OverallDistance += PrefDirElement.Length01;
14950  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
14951  {
14952  if(x == 0)
14953  {
14954  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
14955  }
14956  else
14957  {
14958  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
14959  {
14960  OverallSpeedLimit = -1;
14961  }
14962  }
14963  }
14964  }
14965  }
14966  Utilities->CallLogPop(1529);
14967 }
14968 
14969 // ---------------------------------------------------------------------------
14970 
14971 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
14972 {
14973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
14974  if(PrefDirSize() == 0)
14975  {
14976  Utilities->CallLogPop(1564);
14977  return;
14978  }
14979  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
14980  bool FoundFlag;
14982  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
14983 
14984  while(MMIT != PrefDir4MultiMap.end())
14985  {
14986  HLoc = MMIT->first.first;
14987  VLoc = MMIT->first.second;
14988  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14989  H = HLoc - Track->GetHLocMin();
14990  V = VLoc - Track->GetVLocMin();
14991  // always found in order, any missing have PrefDirPosx == -1
14992  if(PrefDirPos0 > -1)
14993  {
14994  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
14995  }
14996  if(PrefDirPos1 > -1)
14997  {
14998  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
14999  }
15000  if(PrefDirPos2 > -1)
15001  {
15002  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
15003  }
15004  if(PrefDirPos3 > -1)
15005  {
15006  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
15007  }
15008  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
15009  {
15010  // need to plot all 4 in order to obtain all the direction graphics
15011  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
15012  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
15013  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
15014  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
15015  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
15016  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
15017  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
15018  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
15019  MMIT++;
15020  MMIT++;
15021  MMIT++;
15022  MMIT++;
15023  }
15024  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
15025  {
15026  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
15027  {
15028  // 0 & 1 constitute the bidirectional PrefDir
15029  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
15030  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
15031  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
15032  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
15033  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
15034  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
15035  MMIT++;
15036  MMIT++;
15037  MMIT++;
15038  }
15039  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
15040  {
15041  // 0 & 2 constitute the bidirectional PrefDir
15042  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
15043  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
15044  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
15045  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
15046  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
15047  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
15048  MMIT++;
15049  MMIT++;
15050  MMIT++;
15051  }
15052  else
15053  {
15054  // 1 & 2 constitute the bidirectional PrefDir
15055  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
15056  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
15057  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
15058  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
15059  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
15060  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
15061  MMIT++;
15062  MMIT++;
15063  MMIT++;
15064  }
15065  }
15066  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
15067  {
15068  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
15069  {
15070  // 0 & 1 constitute the bidirectional PrefDir
15071  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
15072  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
15073  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
15074  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
15075  MMIT++;
15076  MMIT++;
15077  }
15078  else
15079  {
15080  // 2 unidirectional PrefDirs
15081  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
15082  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
15083  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
15084  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
15085  MMIT++;
15086  MMIT++;
15087  }
15088  }
15089  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
15090  {
15091  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
15092  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
15093  MMIT++;
15094  }
15095  }
15096  Utilities->CallLogPop(1565);
15097 }
15098 
15099 // ---------------------------------------------------------------------------
15100 
15101 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
15102 /*
15103  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
15104  level crossing, signals with wrong direction set, or buffers.
15105 */
15106 {
15107  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
15108  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15109  bool FoundFlag;
15111  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
15112 
15113  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
15114  ElementIn.VLoc)))
15115  {
15116  Utilities->CallLogPop(1982);
15117  return(false);
15118  }
15119  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at entry end, i.e. against preferred direction
15120  {
15121  Utilities->CallLogPop(1983);
15122  return(false);
15123  }
15124 /* if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal)) //ground signal allowed at v2.14.0
15125  {
15126  Utilities->CallLogPop(1995);
15127  return(false);
15128  }
15129 */
15130 // Now check that there is only a single prefdir set
15131  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15132 // always found in order, any missing have PrefDirPosx == -1
15133  if(PrefDirPos0 > -1)
15134  {
15135  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
15136  }
15137  if(PrefDirPos1 > -1)
15138  {
15139  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
15140  }
15141  if(PrefDirPos2 > -1)
15142  {
15143  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
15144  }
15145  if(PrefDirPos3 > -1)
15146  {
15147  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
15148  }
15149  if(PrefDirPos3 > -1) // 4 found, all bidirectional
15150  {
15151  Utilities->CallLogPop(1984);
15152  return(false);
15153  }
15154  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
15155  {
15156  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
15157  {
15158  Utilities->CallLogPop(1985);
15159  return(false);
15160  }
15161  else
15162  {
15163  Utilities->CallLogPop(1986);
15164  return(true);
15165  }
15166  }
15167  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
15168  {
15169  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
15170  {
15171  Utilities->CallLogPop(1987);
15172  return(false);
15173  }
15174  else
15175  {
15176  Utilities->CallLogPop(1988);
15177  return(true);
15178  }
15179  }
15180  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
15181  {
15182  if(PrefDirElement0.XLinkPos == EntryPos)
15183  {
15184  Utilities->CallLogPop(1989);
15185  return(false);
15186  }
15187  else
15188  {
15189  Utilities->CallLogPop(1990);
15190  return(true);
15191  }
15192  }
15193  else
15194  {
15195  Utilities->CallLogPop(1991);
15196  return(false); // none found
15197  }
15198 }
15199 
15200 // ---------------------------------------------------------------------------
15201 
15203 {
15204 /*
15205  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
15206  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
15207  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
15208  diagonal link are excluded.
15209 
15210  Added at v2.1.0 - Corrects the problem when presetting automatic signal routes, where a route could be set across a
15211  diagonal fouled by adjacent track (i.e. a track element with a diagonal link that touched another track element's
15212  diagonal link). Preset AutoRoutes can't be set across crossovers and a diagonal fouled by a crossing track is equivalent to a crossover.
15213 
15214  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
15215  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
15216  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15217  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15218  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15219  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15220 */
15221  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
15222  ElementIn.VLoc + "," + XLink);
15223  int TrackVecPos;
15224  bool TrackFoundFlag;
15225  TTrackElement TempTrackElement;
15226  //first check that this element at XLink is not itself a buffer/Gap/Continuation
15227  if(((ElementIn.TrackType == Buffers) || (ElementIn.TrackType == GapJump) || (ElementIn.TrackType == Continuation)) && (ElementIn.Link[0] == XLink))
15228  {
15229  Utilities->CallLogPop(2750);
15230  return(false);
15231  }
15232  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
15233  {
15234  Utilities->CallLogPop(2047);
15235  return(false);
15236  }
15237 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
15238  if(XLink == 1)
15239  {
15240  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15241  if(TrackFoundFlag)
15242  {
15243  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
15244  if(!(Track->DiagAtLinkIsBufGapCont(48, TempTrackElement.HLoc, TempTrackElement.VLoc, 3)) &&
15245  ((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3)))
15246  {
15247  Utilities->CallLogPop(2048);
15248  return(true);
15249  }
15250  }
15251  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15252  if(TrackFoundFlag)
15253  {
15254  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
15255  if(!(Track->DiagAtLinkIsBufGapCont(49, TempTrackElement.HLoc, TempTrackElement.VLoc, 7))
15256  && ((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7)))
15257  {
15258  Utilities->CallLogPop(2049);
15259  return(true);
15260  }
15261  }
15262  }
15263 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
15264  if(XLink == 3)
15265  {
15266  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15267  if(TrackFoundFlag)
15268  {
15269  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
15270  if(!(Track->DiagAtLinkIsBufGapCont(50, TempTrackElement.HLoc, TempTrackElement.VLoc, 1))
15271  && ((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1)))
15272  {
15273  Utilities->CallLogPop(2050);
15274  return(true);
15275  }
15276  }
15277  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
15278  if(TrackFoundFlag)
15279  {
15280  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
15281  if(!(Track->DiagAtLinkIsBufGapCont(51, TempTrackElement.HLoc, TempTrackElement.VLoc, 9))
15282  && ((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9)))
15283  {
15284  Utilities->CallLogPop(2051);
15285  return(true);
15286  }
15287  }
15288  }
15289 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
15290  if(XLink == 7)
15291  {
15292  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
15293  if(TrackFoundFlag)
15294  {
15295  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
15296  if(!(Track->DiagAtLinkIsBufGapCont(52, TempTrackElement.HLoc, TempTrackElement.VLoc, 9))
15297  && ((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9)))
15298  {
15299  Utilities->CallLogPop(2052);
15300  return(true);
15301  }
15302  }
15303  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15304  if(TrackFoundFlag)
15305  {
15306  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
15307  if(!(Track->DiagAtLinkIsBufGapCont(53, TempTrackElement.HLoc, TempTrackElement.VLoc, 1))
15308  && ((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1)))
15309  {
15310  Utilities->CallLogPop(2053);
15311  return(true);
15312  }
15313  }
15314  }
15315 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
15316  if(XLink == 9)
15317  {
15318  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
15319  if(TrackFoundFlag)
15320  {
15321  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
15322  if(!(Track->DiagAtLinkIsBufGapCont(54, TempTrackElement.HLoc, TempTrackElement.VLoc, 7))
15323  && ((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7)))
15324  {
15325  Utilities->CallLogPop(2054);
15326  return(true);
15327  }
15328  }
15329  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
15330  if(TrackFoundFlag)
15331  {
15332  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
15333  if(!(Track->DiagAtLinkIsBufGapCont(55, TempTrackElement.HLoc, TempTrackElement.VLoc, 3))
15334  && ((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3)))
15335  {
15336  Utilities->CallLogPop(2055);
15337  return(true);
15338  }
15339  }
15340  }
15341  Utilities->CallLogPop(2056);
15342  return(false);
15343 }
15344 
15345 // ---------------------------------------------------------------------------
15346 
15347 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
15348 {
15349 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
15350  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
15351  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
15352  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
15353  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
15354 */
15355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
15357  bool FoundFlag, ContFlag, FoundElements = false;
15358  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
15359  TPrefDirElement NextElement;
15360 
15361  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
15362  {
15363  LastIteratorValue++;
15364  ContFlag = false;
15365  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
15366  {
15367  continue;
15368  }
15369 /* if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal)) //ground signal start permitted at v2.14.0
15370  {
15371  continue;
15372  }
15373 */
15374 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be
15375 //at end of an existing route
15376 // found a potential route start point
15377  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
15378  {
15379  continue;
15380  }
15381  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
15382  {
15383  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
15384  if(PDVIt->TrackType == Continuation)
15385  {
15386  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
15387  {
15388  continue;
15389  }
15390  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
15391  {
15392  continue;
15393  }
15394  }
15395  StartElement = *PDVIt;
15396 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked
15397  //to diverging track on which there was no pref dir. See below for 2 required changes.
15398  }
15399  else
15400  {
15401  continue;
15402  }
15403  // now track along until find a signal or continuation, checking validity for each element
15404  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
15405  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
15406  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15407  if(PrefDirPos0 == -1) // no continuing prefdir
15408  {
15409  continue;
15410  }
15411  bool NextElementFoundFlag = false;
15412  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15413  {
15414  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
15415  NextElementFoundFlag = true;
15416  }
15417  if(PrefDirPos1 > -1)
15418  {
15419  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15420  {
15421  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
15422  NextElementFoundFlag = true;
15423  }
15424  }
15425  if(PrefDirPos2 > -1)
15426  {
15427  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15428  {
15429  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
15430  NextElementFoundFlag = true;
15431  }
15432  }
15433  if(PrefDirPos3 > -1)
15434  {
15435  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
15436  {
15437  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
15438  NextElementFoundFlag = true;
15439  }
15440  }
15441  if(!NextElementFoundFlag)
15442  {
15443  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15444 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
15445  }
15446  while(true)
15447  {
15448  // check validity
15449  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
15450  {
15451  ContFlag = true;
15452  break;
15453  }
15454  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
15455  {
15456  ContFlag = true;
15457  break;
15458  }
15459  // check if in a route, providing not a signal, as a signal might be at the start of a route
15460  if(NextElement.TrackType != SignalPost)
15461  {
15462  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
15463  {
15464  ContFlag = true;
15465  break;
15466  }
15467  }
15468  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
15469  // can't be a gound signal as would have failed the validity test - can be at v2.14.0
15470  {
15471  EndElement = NextElement;
15472  break;
15473  }
15474  // get the next element in the sequence
15475  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
15476  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
15477  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15478  if(PrefDirPos0 == -1) // no continuing prefdir
15479  {
15480  ContFlag = true;
15481  break;
15482  }
15483  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15484  {
15485  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
15486  continue;
15487  }
15488  if(PrefDirPos1 > -1)
15489  {
15490  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15491  {
15492  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
15493  continue;
15494  }
15495  }
15496  if(PrefDirPos2 > -1)
15497  {
15498  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15499  {
15500  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
15501  continue;
15502  }
15503  }
15504  if(PrefDirPos3 > -1)
15505  {
15506  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
15507  {
15508  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
15509  continue;
15510  }
15511  }
15512  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
15513  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
15514  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
15515  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
15516  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
15517  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
15518  {
15519  ContFlag = true;
15520  break;
15521  }
15522  else
15523  {
15524  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
15525  // could drop the bridge test but keep it to show the change history
15526  break;
15527 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
15528  }
15529  }
15530  if(ContFlag)
15531  {
15532  continue;
15533  }
15534  // else have start and end elements set & all elements valid, so set up the route segment
15535  FoundElements = true;
15536  break;
15537  }
15538  if(FoundElements)
15539  {
15540  Utilities->CallLogPop(1992);
15541  return(true);
15542  }
15543  else
15544  {
15545  Utilities->CallLogPop(1993);
15546  return(false);
15547  }
15548 }
15549 
15550 // ---------------------------------------------------------------------------
15551 // TOneRoute
15552 // ---------------------------------------------------------------------------
15553 
15554 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
15555 {
15556 /* General:
15557  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
15558  containing all the new elements to form the route. When complete, the SearchVector is converted into route
15559  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
15560  route will use automatic signals or not.
15561  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
15562  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
15563  elements, so additional work is needed to complete all their members before they are ready for conversion into
15564  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
15565  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
15566  ConvertAndAdd.......
15567 */
15568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15569  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
15570  ClearRoute();
15571  int TrackVectorPosition;
15572  TTrackElement TrackElement;
15573  TPrefDirElement FirstElement, LastElement;
15574 
15575  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15576  {
15577  Utilities->CallLogPop(199);
15578  return(false);
15579  }
15580  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
15581  {
15582  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
15583  Utilities->CallLogPop(1996);
15584  return(false);
15585  }
15586  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15587  {
15588  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation to start or add to a route, or points to change them");
15589  Utilities->CallLogPop(200);
15590  return(false);
15591  }
15592  if(Track->IsLCAtHV(18, HLoc, VLoc))
15593  {
15594  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
15595  Utilities->CallLogPop(1909);
15596  return(false);
15597  }
15598 // check if selected a train & disallow if so
15599  if(TrackElement.TrainIDOnElement > -1)
15600  {
15601  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
15602  Utilities->CallLogPop(202);
15603  return(false);
15604  }
15605 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15606  TPrefDirElement PrefDirElement;
15607  int LockedVectorNumber;
15608 
15609  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15610  {
15611  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
15612  Utilities->CallLogPop(203);
15613  return(false);
15614  }
15615  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15616  {
15617  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
15618  Utilities->CallLogPop(204);
15619  return(false);
15620  }
15622  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
15623 // signal in an autosig route & follow with a non-autosig route
15624 
15625  TPrefDirElement BlankElement;
15626 
15627  StartElement1 = BlankElement;
15628  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
15629 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
15630  bool InPrefDirFlag = false;
15631 
15632  bool FoundFlag;
15633  int PrefDirPos0 = -1;
15634  int PrefDirPos1 = -1;
15635  int PrefDirPos2 = -1;
15636  int PrefDirPos3 = -1;
15637 
15639  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15640  int PrefDirVecPos[4] =
15641  {
15642  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15643  };
15644 
15645  for(int x = 0; x < 4; x++)
15646  {
15647  int b = PrefDirVecPos[x];
15648  if(b > -1)
15649  {
15650  // only allow the appropriate exit route to be searched
15651  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
15652  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
15653  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
15654  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
15655  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
15656  {
15657  InPrefDirFlag = true;
15658  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
15659  if(AutoSigsFlag)
15660  {
15661  StartElement1.AutoSignals = true;
15662  }
15663  StartElement1.PrefDirRoute = true;
15664  }
15665  }
15666  }
15667 
15668  if(!InPrefDirFlag)
15669  {
15670  TrainController->StopTTClockMessage(12, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15671  Utilities->CallLogPop(205);
15672  return(false);
15673  }
15674 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
15676  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15677 
15678  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
15679  {
15680  throw Exception("Selection in two routes - should never happen!");
15681  }
15682  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
15683  {
15684  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15685  {
15686  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
15687  Utilities->CallLogPop(206);
15688  return(false);
15689  }
15690  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
15691  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15692  {
15693  TrainController->StopTTClockMessage(14, "No forward connection from this position");
15694  Utilities->CallLogPop(207);
15695  return(false);
15696  }
15697  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
15698  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15699  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15700  { //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
15701 // TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
15702 // Utilities->CallLogPop(208);
15703 // return(false);
15704  }
15705  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
15707  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
15708  if(AutoSigsFlag)
15709  {
15710  StartElement1.AutoSignals = true;
15711  }
15712  StartElement1.PrefDirRoute = true;
15714  Utilities->CallLogPop(209);
15715  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
15716  }
15717 
15718  else // no route started
15719  {
15720 // check if selected position is adjacent to start or end of an existing route and disallow
15721  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15722  {
15723  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
15724  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15725  {
15726  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
15727  Utilities->CallLogPop(210);
15728  return(false);
15729  }
15730  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15731  {
15732  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
15733  Utilities->CallLogPop(211);
15734  return(false);
15735  }
15736  }
15737 
15738 // check if it's adjacent to end of an existing route,
15739  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15740  {
15742  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15743  {
15744  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
15745  Utilities->CallLogPop(212);
15746  return(false);
15747  }
15748  }
15749  SearchVector.push_back(StartElement1);
15750  Utilities->CallLogPop(213);
15751  return(true);
15752  }
15753 }
15754 
15755 // ---------------------------------------------------------------------------
15756 
15757 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
15758  IDInt &ReqPosRouteID, bool &PointsChanged)
15759 
15760 /*
15761  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
15762 
15763  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
15764  this being set to -1 for not used.
15765  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
15766  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
15767  Check correct type of element - signal/buffers/continuation.
15768  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
15769  EndElement2 corresponding to the 2 possible PrefDir elements).
15770  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
15771  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
15772  linked forward to another route.
15773  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
15774  for same position as start should cover this)
15775 
15776  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
15777  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
15778  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
15779  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
15780  If the search fails then return false.
15781  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
15782  in the SearchVector to ensure it's entered as part of the new route.
15783  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
15784  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
15785  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
15786  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
15787  so return false, with an appropriate message if ConsecSignalsRoute set.
15788 */
15789 
15790 {
15791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
15792  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
15793  int EndPosition; // the position selected
15794  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
15795 
15796  Track->LCFoundInAutoSigsRoute = false;
15798  TotalSearchCount = 0;
15799  ReqPosRouteID = IDInt(-1); // default value for not used
15800  TTrackElement TrackElement;
15801  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
15802  // given element as can't select 2-track elements
15803  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15804  {
15805  Utilities->CallLogPop(214);
15806  return(false);
15807  }
15808  if(Track->IsLCAtHV(19, HLoc, VLoc))
15809  {
15810  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
15811  Utilities->CallLogPop(1908);
15812  return(false);
15813  }
15814 // cancel selection if on original start element
15815  if(EndPosition == StartRoutePosition)
15816  {
15817  Utilities->CallLogPop(215);
15818  return(false);
15819  }
15820  if(AutoSigsFlag)
15821  {
15822  if(TrackElement.TrackType == Buffers)
15823  {
15824  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
15825  Utilities->CallLogPop(216);
15826  return(false);
15827  }
15828  }
15829  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
15830  {
15831  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
15832  Utilities->CallLogPop(217);
15833  return(false);
15834  }
15835 // check if train on element
15836  if(TrackElement.TrainIDOnElement > -1)
15837  {
15838  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
15839  Utilities->CallLogPop(219);
15840  return(false);
15841  }
15842 // disallow if not in EveryPrefDir & set EndElement(s)
15843  bool InPrefDirFlag = false;
15844 
15845  bool FoundFlag;
15846  int PrefDirPos0 = -1;
15847  int PrefDirPos1 = -1;
15848  int PrefDirPos2 = -1;
15849  int PrefDirPos3 = -1;
15850 
15851  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
15852  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15853  int PrefDirVecPos[4] =
15854  {
15855  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15856  };
15857 
15858  for(int x = 0; x < 4; x++)
15859  {
15860  int b = PrefDirVecPos[x];
15861  if(b > -1)
15862  {
15863  InPrefDirFlag = true;
15864  if(EndElement1.TrackVectorPosition == -1)
15865  {
15866  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
15867  }
15868  else
15869  {
15870  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
15871  }
15872  }
15873  }
15874  if(!InPrefDirFlag)
15875  {
15876  TrainController->StopTTClockMessage(23, "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
15877  Utilities->CallLogPop(220);
15878  return(false);
15879  }
15880 // check if in an existing route - can't be a bridge so can use a simple 'find'
15881 // bool InRoute = false;
15883  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15884 
15885  if(RoutePair.first > -1)
15886  {
15887  if(RoutePair.second != 0) // not first element in existing route so no good
15888  {
15889  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
15890  Utilities->CallLogPop(221);
15891  return(false);
15892  }
15893  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
15894 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15895  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
15896  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15897  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
15898  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15899  {
15900  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
15901  Utilities->CallLogPop(222);
15902  return(false);
15903  }
15904  EndElement1 = RouteElement;
15905  EndElement2 = BlankElement; // only need the route element
15906  EndPosition = EndElement1.TrackVectorPosition;
15907  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
15908  }
15909 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15910 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15911 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15912 
15913  if(EndElement1.HLoc >= StartElement1.HLoc)
15914  {
15916  SearchLimitHighH = EndElement1.HLoc + 15;
15917  }
15918  else
15919  {
15920  SearchLimitLowH = EndElement1.HLoc - 15;
15922  }
15923  if(EndElement1.VLoc >= StartElement1.VLoc)
15924  {
15926  SearchLimitHighV = EndElement1.VLoc + 15;
15927  }
15928  else
15929  {
15930  SearchLimitLowV = EndElement1.VLoc - 15;
15932  }
15933 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15934  check & TotalSearchCounts check
15935  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15936  {
15937  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
15938  Utilities->CallLogPop(1693);
15939  return false;
15940  }
15941 */
15942 // check if adjacent to start and disallow
15943  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15944  {
15946  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
15947 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
15948 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
15949  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15950  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15951  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
15952  {
15953  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
15954  Utilities->CallLogPop(223);
15955  return(false);
15956  }
15957 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15958 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
15959  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15960  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15961  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
15962  {
15963  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
15964  Utilities->CallLogPop(224);
15965  return(false);
15966  }
15967 // check if adjacent to end of a route & disallow
15969  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
15970  {
15971  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
15972  Utilities->CallLogPop(225);
15973  return(false);
15974  }
15975  }
15976 
15977 // check for same route as start element
15979  {
15980  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
15981  Utilities->CallLogPop(226);
15982  return(false);
15983  }
15984 // check for a looping route
15985  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15986  {
15988  {
15989  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
15990  Utilities->CallLogPop(1844);
15991  return(false);
15992  }
15993  }
15994 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15995 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
15996 // and don't want to add it again
15997  if(StartSelectionRouteID > -1)
15998  {
15999  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16000  AutoSigsFlag, false))
16001  {
16002  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
16003  if(PointsToBeChanged(5, NewFailedPointsTVPos))
16004  {
16005  if(NewFailedPointsTVPos > -1)
16006  {
16007  TTrackElement TE = Track->TrackElementAt(1478, NewFailedPointsTVPos);
16008  TrainController->StopTTClockMessage(97, "Points at " + TE.ElementID +
16009  " failed during route setting.");
16010  Utilities->CallLogPop(2488);
16011  return(false);
16012  }
16013  PointsChanged = true;
16014  }
16015  Utilities->CallLogPop(227);
16016  return(true);
16017  }
16018  else if(!Track->SuppressRouteFailMessage)
16019  {
16020  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
16022  Utilities->CallLogPop(228);
16023  return(false);
16024  }
16025  }
16026  else
16027  {
16028 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
16029 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
16030 
16031 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
16032 // note that a blank element will have XLinkPos set to -1
16033  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
16034  {
16035  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16036  AutoSigsFlag, false))
16037  {
16038  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
16039  if(PointsToBeChanged(6, NewFailedPointsTVPos))
16040  {
16041  if(NewFailedPointsTVPos > -1)
16042  {
16043  TTrackElement TE = Track->TrackElementAt(1480, NewFailedPointsTVPos);
16044  TrainController->StopTTClockMessage(99, "Points at " + TE.ElementID +
16045  " failed during route setting.");
16046  Utilities->CallLogPop(2490);
16047  return(false);
16048  }
16049  PointsChanged = true;
16050  }
16051  Utilities->CallLogPop(229);
16052  return(true);
16053  }
16054  else
16055  {
16057  {
16059  }
16060  Utilities->CallLogPop(230);
16061  return(false);
16062  }
16063  }
16064  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
16065  {
16066  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16067  AutoSigsFlag, false))
16068  {
16069  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
16070  if(PointsToBeChanged(7, NewFailedPointsTVPos))
16071  {
16072  if(NewFailedPointsTVPos > -1)
16073  {
16074  TTrackElement TE = Track->TrackElementAt(1482, NewFailedPointsTVPos);
16075  TrainController->StopTTClockMessage(101, "Points at " + TE.ElementID +
16076  " failed during route setting.");
16077  Utilities->CallLogPop(2492);
16078  return(false);
16079  }
16080  PointsChanged = true;
16081  }
16082  Utilities->CallLogPop(231);
16083  return(true);
16084  }
16085  else
16086  {
16088  {
16090  }
16091  Utilities->CallLogPop(232);
16092  return(false);
16093  }
16094  }
16095  // now start off in the best direction
16096  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
16097  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
16098  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
16099  // unless new problems are found.
16100  if(StartElement1.XLinkPos == BestPos)
16101  {
16102  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16103  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16104  AutoSigsFlag, false))
16105  {
16106  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
16107  if(PointsToBeChanged(8, NewFailedPointsTVPos))
16108  {
16109  if(NewFailedPointsTVPos > -1)
16110  {
16111  TTrackElement TE = Track->TrackElementAt(1484, NewFailedPointsTVPos);
16112  TrainController->StopTTClockMessage(103, "Points at " + TE.ElementID +
16113  " failed during route setting.");
16114  Utilities->CallLogPop(2494);
16115  return(false);
16116  }
16117  PointsChanged = true;
16118  }
16119  Utilities->CallLogPop(233);
16120  return(true);
16121  }
16122  else if(StartElement2.TrackVectorPosition > -1)
16123  {
16124  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16125  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16126  AutoSigsFlag, false))
16127  {
16128  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
16129  if(PointsToBeChanged(9, NewFailedPointsTVPos))
16130  {
16131  if(NewFailedPointsTVPos > -1)
16132  {
16133  TTrackElement TE = Track->TrackElementAt(1486, NewFailedPointsTVPos);
16134  TrainController->StopTTClockMessage(105, "Points at " + TE.ElementID +
16135  " failed during route setting.");
16136  Utilities->CallLogPop(2496);
16137  return(false);
16138  }
16139  PointsChanged = true;
16140  }
16141  Utilities->CallLogPop(234);
16142  return(true);
16143  }
16144  }
16145  }
16146  else if(StartElement2.TrackVectorPosition > -1)
16147  {
16148  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16149  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16150  AutoSigsFlag, false))
16151  {
16152  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
16153  if(PointsToBeChanged(10, NewFailedPointsTVPos))
16154  {
16155  if(NewFailedPointsTVPos > -1)
16156  {
16157  TTrackElement TE = Track->TrackElementAt(1488, NewFailedPointsTVPos);
16158  TrainController->StopTTClockMessage(107, "Points at " + TE.ElementID +
16159  " failed during route setting.");
16160  Utilities->CallLogPop(2498);
16161  return(false);
16162  }
16163  PointsChanged = true;
16164  }
16165  Utilities->CallLogPop(1857);
16166  return(true);
16167  }
16168  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16169  AutoSigsFlag, false))
16170  {
16171  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
16172  if(PointsToBeChanged(11, NewFailedPointsTVPos))
16173  {
16174  if(NewFailedPointsTVPos > -1)
16175  {
16176  TTrackElement TE = Track->TrackElementAt(1490, NewFailedPointsTVPos);
16177  TrainController->StopTTClockMessage(109, "Points at " + TE.ElementID +
16178  " failed during route setting.");
16179  Utilities->CallLogPop(2500);
16180  return(false);
16181  }
16182  PointsChanged = true;
16183  }
16184  Utilities->CallLogPop(1858);
16185  return(true);
16186  }
16187  }
16188  else if(StartElement1.XLinkPos == (1 - BestPos))
16189  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
16190  {
16191  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16192  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16193  AutoSigsFlag, false))
16194  {
16195  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
16196  if(PointsToBeChanged(12, NewFailedPointsTVPos))
16197  {
16198  if(NewFailedPointsTVPos > -1)
16199  {
16200  TTrackElement TE = Track->TrackElementAt(1492, NewFailedPointsTVPos);
16201  TrainController->StopTTClockMessage(111, "Points at " + TE.ElementID +
16202  " failed during route setting.");
16203  Utilities->CallLogPop(2502);
16204  return(false);
16205  }
16206  PointsChanged = true;
16207  }
16208  Utilities->CallLogPop(1864);
16209  return(true);
16210  }
16211  }
16212  }
16214  {
16216  }
16217  Utilities->CallLogPop(235);
16218  return(false);
16219 }
16220 
16221 // ---------------------------------------------------------------------------
16222 
16223 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
16224 {
16225  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
16226  if(PrefDirSize() == 0)
16227  {
16228  Utilities->CallLogPop(1704);
16229  return;
16230  }
16231  for(unsigned int x = 0; x < PrefDirSize(); x++)
16232  {
16233  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
16234  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
16235  {
16236  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16237  TempPrefDirElement.EXGraphicPtr);
16238  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
16239  {
16240  if(x == 0)
16241  {
16242  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16243  TempPrefDirElement.EntryDirectionGraphicPtr);
16244  }
16245  if(x == (PrefDirSize() - 1))
16246  {
16247  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
16248  TempPrefDirElement.EntryDirectionGraphicPtr);
16249  }
16250  }
16251  }
16252  }
16253 
16254  Utilities->CallLogPop(1705);
16255 }
16256 
16257 // ---------------------------------------------------------------------------
16258 
16259 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
16260  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag, bool RecursiveCall)
16261 /*
16262  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
16263  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
16264  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
16265  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
16266  Return false if any element (apart from RequiredPosition) is on an existing route.
16267  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
16268 
16269  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
16270  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
16271  added during the function so as to leave it exactly as it was on entering, then return false).
16272  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
16273  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
16274  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
16275  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
16276  the route number that the searched-for element is the start of if any, and set to -1 if no
16277  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
16278  this unit, together with the ConsecSignals and AutoSigsFlag flags.
16279  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
16280  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
16281 
16282  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
16283  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
16284  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
16285  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
16286  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
16287  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
16288  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16289  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
16290  or if train on element (unless a bridge & train on different track).
16291  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
16292  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
16293  a leading point where both trailing directions are in EveryPrefDir, if not fail.
16294  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
16295  AutoSignals member set if AutoSigsFlag set, then return true.
16296  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
16297 
16298  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
16299  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
16300  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
16301  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
16302  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
16303  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
16304  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
16305 
16306  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
16307  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
16308 */
16309 
16310 {
16311  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
16312  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
16313  AnsiString((short)AutoSigsFlag) + "," + AnsiString((short)RecursiveCall));
16314  int VectorCount = 0;
16315  if(!RecursiveCall) //added at v2.15.1
16316  {
16318  }
16319 
16320  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
16321 
16322 // check for a fouled diagonal for first element. Added for v1.3.2
16323  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
16324  {
16325  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
16326  {
16327  for(int x = 0; x < VectorCount; x++)
16328  {
16329  SearchVector.erase(SearchVector.end() - 1);
16330  }
16331  Utilities->CallLogPop(2043);
16332  return(false);
16333  }
16334  }
16335  bool FirstPass = true;
16336 
16337  while(true)
16338  {
16339  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
16340  {
16341  Track->LCFoundInAutoSigsRoute = true;
16342  }
16343  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
16344  {
16345  for(int x = 0; x < VectorCount; x++)
16346  {
16347  SearchVector.erase(SearchVector.end() - 1);
16348  }
16349  Utilities->CallLogPop(1926);
16350  return(false);
16351  }
16352  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
16353  {
16354  for(int x = 0; x < VectorCount; x++)
16355  {
16356  SearchVector.erase(SearchVector.end() - 1);
16357  }
16358  Utilities->CallLogPop(236);
16359  return(false);
16360  }
16361  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
16362  // reached a valid signal that isn't the required position, user should always select the next
16363  // signal in a route when ConsecSignals is true so have to fail
16364  // won't affect recurive searches as for them the first pass element is always a point
16365  {
16366  for(int x = 0; x < VectorCount; x++)
16367  {
16368  SearchVector.erase(SearchVector.end() - 1);
16369  }
16370  Utilities->CallLogPop(237);
16371  return(false);
16372  }
16373  FirstPass = false;
16374  int NextPosition = PrefDirElement.Conn[XLinkPos];
16375  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
16376  TPrefDirElement SearchElement(NextTrackElement);
16377  SearchElement.TrackVectorPosition = NextPosition;
16378  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
16379  SearchElement.ELinkPos = NextELinkPos;
16380  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
16381  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
16382  int NextXLinkPos;
16383  if(SearchElement.ELinkPos == 0)
16384  {
16385  NextXLinkPos = 1;
16386  }
16387  if(SearchElement.ELinkPos == 1)
16388  {
16389  NextXLinkPos = 0;
16390  }
16391  if(SearchElement.ELinkPos == 2)
16392  {
16393  NextXLinkPos = 3;
16394  }
16395  if(SearchElement.ELinkPos == 3)
16396  {
16397  NextXLinkPos = 2;
16398  }
16399  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16400  {
16401  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16402 // note that may be buffers, continuation or gap
16403  SearchElement.XLinkPos = NextXLinkPos;
16404  }
16405 // can't set XLink or XLinkPos yet if the element is a non-failed leading point.
16406 
16407 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16408  drop this at v2.16.1 as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of points and
16409  crossovers as can reach element on opposite track and still find the required end point - causes error when adding to the Route2MultiMap
16410  (happened by chance when developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search
16411  through all searchvector.
16412 
16413  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
16414 */
16415  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
16416  {
16417  for(unsigned int x = 0; x < SearchVector.size(); x++)
16418  {
16419  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
16420  {
16421  for(int x = 0; x < VectorCount; x++)
16422  {
16423  SearchVector.erase(SearchVector.end() - 1);
16424  }
16425  Utilities->CallLogPop(2653);
16426  return(false);
16427  }
16428  }
16429  }
16430  else if(SearchElement.TrackType == Bridge)
16431  {
16432  for(unsigned int x = 0; x < SearchVector.size(); x++)
16433  {
16434  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
16435  (SearchElement.ELink == SearchVector.at(x).ELink))
16436  {
16437  for(int x = 0; x < VectorCount; x++)
16438  {
16439  SearchVector.erase(SearchVector.end() - 1);
16440  }
16441  Utilities->CallLogPop(2654);
16442  return(false);
16443  }
16444  }
16445  }
16446 
16447 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16448  TAllRoutes::TRouteElementPair SecondPair;
16450  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16451  if(RoutePair.first > -1)
16452  {
16453  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16454  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
16455  RoutePair.second).ELinkPos)))
16456  {
16457  // still OK if start of an expected route
16458  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
16459  {
16460  for(int x = 0; x < VectorCount; x++)
16461  {
16462  SearchVector.erase(SearchVector.end() - 1);
16463  }
16464  Utilities->CallLogPop(239);
16465  return(false); // only allow for start of an expected route
16466  }
16467  }
16468  }
16469  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16470  {
16471  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16472  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
16473  SecondPair.second).ELinkPos)))
16474  {
16475  // still OK if start of an expected route
16476  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
16477  {
16478  for(int x = 0; x < VectorCount; x++)
16479  {
16480  SearchVector.erase(SearchVector.end() - 1);
16481  }
16482  Utilities->CallLogPop(240);
16483  return(false); // only allow for start of an expected route
16484  }
16485  }
16486  }
16487 // check if a train on element, unless a bridge & train on different track
16488 // OK of same train as start element - no drop this
16489 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16490  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16491  {
16492  for(int x = 0; x < VectorCount; x++)
16493  {
16494  SearchVector.erase(SearchVector.end() - 1);
16495  }
16496  Utilities->CallLogPop(241);
16497  return(false);
16498  }
16499  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16500  {
16501  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
16502  {
16503  for(int x = 0; x < VectorCount; x++)
16504  {
16505  SearchVector.erase(SearchVector.end() - 1);
16506  }
16507  Utilities->CallLogPop(242);
16508  return(false);
16509  }
16510  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
16511  {
16512  for(int x = 0; x < VectorCount; x++)
16513  {
16514  SearchVector.erase(SearchVector.end() - 1);
16515  }
16516  Utilities->CallLogPop(243);
16517  return(false);
16518  }
16519  }
16520 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
16521  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16522  {
16523  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16524  {
16525  for(int x = 0; x < VectorCount; x++)
16526  {
16527  SearchVector.erase(SearchVector.end() - 1);
16528  }
16529  Utilities->CallLogPop(244);
16530  return(false);
16531  }
16532  }
16533 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
16534 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
16535  bool InPrefDirFlag = false;
16536  PrefDirElement1 = BlankElement;
16537  PrefDirElement2 = BlankElement;
16538 
16539  bool FoundFlag;
16540  int PrefDirPos0 = -1;
16541  int PrefDirPos1 = -1;
16542  int PrefDirPos2 = -1;
16543  int PrefDirPos3 = -1;
16545  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
16546  int PrefDirVecPos[4] =
16547  {
16548  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
16549  };
16550  for(int x = 0; x < 4; x++)
16551  {
16552  int b = PrefDirVecPos[x];
16553  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
16554  {
16555  InPrefDirFlag = true;
16556  if(PrefDirElement1.TrackVectorPosition == -1)
16557  {
16558  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
16559  }
16560  else
16561  {
16562  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
16563  }
16564  }
16565  }
16566  if(!InPrefDirFlag)
16567  {
16568  for(int x = 0; x < VectorCount; x++)
16569  {
16570  SearchVector.erase(SearchVector.end() - 1);
16571  }
16572  Utilities->CallLogPop(245);
16573  return(false);
16574  }
16575 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16576 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16577 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16579  {
16580  for(int x = 0; x < VectorCount; x++)
16581  {
16582  SearchVector.erase(SearchVector.end() - 1);
16583  }
16584  Utilities->CallLogPop(1690);
16585  return(false);
16586  }
16587 // check if found it
16588  if(SearchElement.TrackVectorPosition == RequiredPosition)
16589  {
16590 // need to ensure a signal/buffer/continuation
16591 // if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End)) dropped at v2.16.1 - may find element round a loop and appear invalid when in fact valid
16592  if((SearchElement.TrackType != SignalPost) && (SearchElement.TrackType != Buffers) && (SearchElement.TrackType != Continuation)) //added at v2.16.1
16593  {
16594  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
16596  for(int x = 0; x < VectorCount; x++)
16597  {
16598  SearchVector.erase(SearchVector.end() - 1);
16599  }
16600  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1 (to stop several same messages being given)
16601  Utilities->CallLogPop(246);
16602  return(false);
16603  } // if((SearchElement.TrackType != SignalPost) &&.......
16604 //need to make sure it's in the right direction
16605  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End))
16606  { //condition added at v2.16.1
16607  for(int x = 0; x < VectorCount; x++)
16608  {
16609  SearchVector.erase(SearchVector.end() - 1);
16610  }
16611  Utilities->CallLogPop(2627);
16612  return(false);
16613  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal)......
16614 
16615  if(AutoSigsFlag)
16616  {
16617  PrefDirElement1.AutoSignals = true;
16618  }
16619  PrefDirElement1.PrefDirRoute = true;
16621  {
16623  {
16624  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
16626  }
16627  for(int x = 0; x < VectorCount; x++)
16628  {
16629  SearchVector.erase(SearchVector.end() - 1);
16630  }
16631  QuitAllRecursiveSearchesFlag = true; //added at v2.15.1
16632  Utilities->CallLogPop(1928);
16633  return(false);
16634  }
16635  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
16636  VectorCount++; // not really needed but include for tidyness
16637  TotalSearchCount++;
16638  if(!RecursiveCall && SignalHasFailed(0)) //added at v2.13.0. SignalHasFailed returns true if a signal somewhere on the route fails, route not set if so
16639  { //has to be the top level call (!RecursiveCall) as only then is the route sue to be set
16640  for(int x = 0; x < VectorCount; x++)
16641  {
16642  SearchVector.erase(SearchVector.end() - 1);
16643  }
16644  Utilities->CallLogPop(2522);
16645  return(false);
16646  }
16647  Utilities->CallLogPop(247);
16648  return(true);
16649  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
16650 
16651 // check if a buffer or continuation (end of search on this leg if not found by now)
16652  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16653  {
16654  for(int x = 0; x < VectorCount; x++)
16655  {
16656  SearchVector.erase(SearchVector.end() - 1);
16657  }
16658  Utilities->CallLogPop(248);
16659  return(false);
16660  }
16661 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
16663  {
16664  for(int x = 0; x < VectorCount; x++)
16665  {
16666  SearchVector.erase(SearchVector.end() - 1);
16667  }
16668  Utilities->CallLogPop(1420);
16669  return(false);
16670  }
16671 //deal with failed points, added at v2.13.0
16672  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1518, SearchElement.TrackVectorPosition).Failed) //leading entry
16673  {
16674  if(Track->TrackElementAt(1519, SearchElement.TrackVectorPosition).Attribute == 0)
16675  {
16676  SearchElement.XLinkPos = 1;
16677  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16678  PrefDirElement1.XLinkPos = 1; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16679  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16680  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16681  }
16682  else
16683  {
16684  SearchElement.XLinkPos = 3;
16685  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
16686  PrefDirElement1.XLinkPos = 3; //need PrefDirElement1 set too as SearchElement set to it ready for next loop
16687  PrefDirElement1.XLink = SearchElement.Link[SearchElement.XLinkPos];
16688  PrefDirElement1.EntryExitNumber(); //to set EXNumber correctly as XLink might have changed for original
16689  }
16690  }
16691  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1520, SearchElement.TrackVectorPosition).Failed) //trailing entry
16692  {
16693  if((Track->TrackElementAt(1521, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
16694  {
16695  for(int x = 0; x < VectorCount; x++)
16696  {
16697  SearchVector.erase(SearchVector.end() - 1);
16698  }
16699  Utilities->CallLogPop(2514);
16700  return(false);
16701  }
16702  if((Track->TrackElementAt(1522, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
16703  {
16704  for(int x = 0; x < VectorCount; x++)
16705  {
16706  SearchVector.erase(SearchVector.end() - 1);
16707  }
16708  Utilities->CallLogPop(2515);
16709  return(false);
16710  }
16711  }
16712 // check if reached a non-failed leading point
16713  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !Track->TrackElementAt(1523, SearchElement.TrackVectorPosition).Failed)
16714  {
16715 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16716  int SearchPos1 = SearchElement.Attribute + 1;
16717  int SearchPos2;
16718  if(SearchPos1 == 2)
16719  {
16720  SearchPos1++;
16721  }
16722  if(SearchPos1 == 1)
16723  {
16724  SearchPos2 = 3;
16725  }
16726  else
16727  {
16728  SearchPos2 = 1;
16729  }
16730  SearchElement.XLink = SearchElement.Link[SearchPos1];
16731  SearchElement.XLinkPos = SearchPos1;
16732  InPrefDirFlag = false;
16733  if(SearchElement.XLink == PrefDirElement1.XLink)
16734  {
16735  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16736  InPrefDirFlag = true;
16737  }
16738  else if(SearchElement.XLink == PrefDirElement2.XLink)
16739  {
16740  SearchElement = PrefDirElement2;
16741  InPrefDirFlag = true;
16742  }
16743 // push element with XLink set to position [SearchPos1] if on a PrefDir
16744  if(InPrefDirFlag)
16745  {
16746 // check for a fouled diagonal for leading point for XLinkPos == 1)
16747  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16748  {
16749  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16750  {
16751  for(int x = 0; x < VectorCount; x++)
16752  {
16753  SearchVector.erase(SearchVector.end() - 1);
16754  }
16755  Utilities->CallLogPop(249);
16756  return(false);
16757  }
16758  }
16759  if(AutoSigsFlag)
16760  {
16761  SearchElement.AutoSignals = true;
16762  }
16763  SearchElement.PrefDirRoute = true;
16764  SearchVector.push_back(SearchElement);
16765  VectorCount++;
16766  TotalSearchCount++;
16767 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16768  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16769  AutoSigsFlag, true))
16770  {
16772  {
16774  {
16775  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
16777  }
16778  for(int x = 0; x < VectorCount; x++)
16779  {
16780  SearchVector.erase(SearchVector.end() - 1);
16781  }
16782  Utilities->CallLogPop(1929);
16783  return(false);
16784  }
16785  if(!RecursiveCall && SignalHasFailed(1)) //added at v2.13.0
16786  {
16787  for(int x = 0; x < VectorCount; x++)
16788  {
16789  SearchVector.erase(SearchVector.end() - 1);
16790  }
16791  Utilities->CallLogPop(2523);
16792  return(false);
16793  }
16794  Utilities->CallLogPop(250);
16795  return(true);
16796  }
16797  else
16798  {
16799 // remove leading point with XLinkPos [1]
16800  if(!QuitAllRecursiveSearchesFlag) //added at v2.15.1
16801  {
16802  SearchVector.erase(SearchVector.end() - 1);
16803  VectorCount--;
16804  }
16805  else
16806  {
16807  for(int x = 0; x < VectorCount; x++)
16808  {
16809  SearchVector.erase(SearchVector.end() - 1);
16810  }
16811  Utilities->CallLogPop(2626);
16812  return(false);
16813  }
16814  }
16815  }
16816 // XLink set to position [SearchPos2]
16817  SearchElement.XLink = SearchElement.Link[SearchPos2];
16818  SearchElement.XLinkPos = SearchPos2;
16819  if(SearchElement.XLink == PrefDirElement1.XLink)
16820  {
16821  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
16822  }
16823  else if(SearchElement.XLink == PrefDirElement2.XLink)
16824  {
16825  SearchElement = PrefDirElement2;
16826  }
16827  else // failed to find a valid exit from the point
16828  {
16829  for(int x = 0; x < VectorCount; x++)
16830  {
16831  SearchVector.erase(SearchVector.end() - 1);
16832  }
16833  Utilities->CallLogPop(251);
16834  return(false);
16835  }
16836 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16837  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16838  {
16839  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16840  {
16841  for(int x = 0; x < VectorCount; x++)
16842  {
16843  SearchVector.erase(SearchVector.end() - 1);
16844  }
16845  Utilities->CallLogPop(252);
16846  return(false);
16847  }
16848  }
16849 // push element with XLink set to position [SearchPos2]
16850  if(AutoSigsFlag)
16851  {
16852  SearchElement.AutoSignals = true;
16853  }
16854  SearchElement.PrefDirRoute = true;
16855  SearchVector.push_back(SearchElement);
16856  VectorCount++;
16857  TotalSearchCount++;
16858 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16859  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
16860  AutoSigsFlag, true))
16861  {
16863  {
16865  {
16866  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
16868  }
16869  for(int x = 0; x < VectorCount; x++)
16870  {
16871  SearchVector.erase(SearchVector.end() - 1);
16872  }
16873  Utilities->CallLogPop(1930);
16874  return(false);
16875  }
16876  if(!RecursiveCall && SignalHasFailed(2)) //added at v2.13.0
16877  {
16878  for(int x = 0; x < VectorCount; x++)
16879  {
16880  SearchVector.erase(SearchVector.end() - 1);
16881  }
16882  Utilities->CallLogPop(2524);
16883  return(false);
16884  }
16885  Utilities->CallLogPop(1592);
16886  return(true);
16887  }
16888  else
16889  {
16890  for(int x = 0; x < VectorCount; x++)
16891  {
16892  SearchVector.erase(SearchVector.end() - 1);
16893  }
16894  Utilities->CallLogPop(253);
16895  return(false);
16896  }
16897  } // if leading point
16898 
16899 // here if ordinary element or failed points, push it, inc vector & update PrefDirElement ready for next element on PrefDir
16900  SearchElement = PrefDirElement1;
16901  if(AutoSigsFlag)
16902  {
16903  SearchElement.AutoSignals = true;
16904  }
16905  SearchElement.PrefDirRoute = true;
16906  SearchVector.push_back(SearchElement);
16907  VectorCount++;
16908  TotalSearchCount++;
16909  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16910  PrefDirElement = SearchElement;
16911  } // while(true)
16912 }
16913 
16914 // ---------------------------------------------------------------------------
16915 
16916 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
16917 {
16918 /*
16919  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
16920  and the new or extended route created from that. Hence action varies depending on whether
16921  it is a completely new route, or an extension of an existing route at the beginning or the end.
16922  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16923  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16924 
16925  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16926  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
16927  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
16928  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
16929  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
16930  is decremented;
16931  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
16932  from the existing route, then enter the new route into the AllRoutesVector;
16933  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16934  then enter the new route into the AllRoutesVector.
16935 
16936  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
16937  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
16938  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
16939  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
16940  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
16941  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
16942  for the new route and return;
16943  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
16944  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
16945 
16946  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
16947  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
16948  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
16949 
16950 */
16951  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
16952  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
16953  if(SearchVector.size() < 1)
16954  {
16955  Utilities->CallLogPop(254);
16956  return;
16957  }
16959  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
16960  {
16961  Utilities->CallLogPop(255);
16962  return;
16963  }
16964  TAllRoutes::TLockedRouteClass LockedRouteObject;
16965 
16967  unsigned int TruncatePrefDirPosition = 0;
16968 
16969  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
16970 /* if have ReqPosRouteID:
16971  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
16972  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
16973  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
16974  the existing route, then enter the new route into the AllRoutesVector
16975  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16976  then enter the new route into the AllRoutesVector
16977 */
16978  {
16981  {
16982  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
16983  x++) // start at 1 as first element already in SearchVector
16984  {
16986  }
16987  // note that route numbers in map adjusted when ReqPos route cleared
16989  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16990  // set during ClearRouteDuringRouteBuildingAt
16992  {
16995  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16996  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16997  }
16998  }
17000  {
17002  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
17003  }
17005  {
17006  SearchVector.pop_back();
17007  }
17008  }
17009  if(StartSelectionRouteID > -1)
17010 /* if have StartSelectionRouteID:
17011  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
17012  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
17013  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
17014  then add it to the start of the new route, then enter the new route into the AllRoutesVector
17015  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
17016 */
17017  {
17019  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
17020  {
17023  {
17024  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
17025  for(unsigned int x = 0; x < SearchVector.size(); x++)
17026  {
17028  RouteNumber, GetFixedSearchElementAt(3, x));
17029  // find & store locked route truncate position in PrefDirVector for later use
17031  {
17032  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
17033  {
17034  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
17035  }
17036  }
17037  }
17039  {
17040  throw Exception("Error - failed to validate extended route for preferred route");
17041  }
17044  if(!AutoSigsFlag)
17045  {
17046  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
17047  }
17048  // now add the reinstated locked route if required and set signals accordingly
17050  {
17051  LockedRouteObject.RouteNumber = RouteNumber;
17052  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
17053  // now reset the signals for the locked route
17054  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
17055  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
17056  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
17057  {
17058  // return all signals to red in route section to be truncated
17059  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
17060  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
17061  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17062  {
17063  TrackElement.Attribute = 0;
17064  Track->PlotSignal(10, TrackElement, Display);
17065  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17066  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17067  }
17068  }
17069  }
17070  AllRoutes->CheckMapAndRoutes(1); // test
17071  Utilities->CallLogPop(256);
17072  return;
17073  }
17075  {
17078  RouteElement.AutoSignals = true;
17079  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
17080  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
17081  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
17082  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
17083  }
17084  }
17085  else
17086  {
17088  }
17089 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
17090 // AllRoutesVector hence nothing to do here
17091  }
17092  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
17093  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
17094  {
17095  throw Exception("Error - failed to validate single route for preferred route");
17096  }
17097  AllRoutes->StoreOneRoute(1, this);
17098  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
17099  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
17100  if(!AutoSigsFlag)
17101  {
17102  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
17103  }
17104  AllRoutes->CheckMapAndRoutes(2); // test
17105  Utilities->CallLogPop(257);
17106 }
17107 
17108 // ---------------------------------------------------------------------------
17109 
17110 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
17111 {
17112 /*
17113  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
17114  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
17115  & ensure signal/buffers/continuation.
17116  Note that can't select ConsecSignalsRoute for non-preferred routes.
17117  Check if train on element & disallow.
17118  Set default values for retained parameters:-
17119  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
17120  StartSelectionRouteID = route that selection starts in if there is one;
17121 
17122  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
17123  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
17124  validity. This is just for safety reasons, the PrefDir values aren't used.
17125  StartElement1 & 2 are set to these PrefDirelements.
17126 
17127  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
17128 
17129  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
17130  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
17131  blank StartElement2 (only want to use the route element), then return true.
17132  Check if adjacent to start or end of an existing route & disallow if so.
17133  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
17134  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
17135  SetRemainingSearchVectorValues().
17136  Finally add the required element to the SearchVector & return true.
17137 
17138 */
17139  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
17140  AnsiString(VLoc) + "," + AnsiString((short)Callon));
17141  ClearRoute();
17142  int TrackVectorPosition;
17143  TTrackElement TrackElement;
17144  TPrefDirElement FirstElement, LastElement;
17145 
17146  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
17147  {
17148  Utilities->CallLogPop(258);
17149  return(false);
17150  }
17151  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17152  {
17153  if(!Callon)
17154  {
17155  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
17156  }
17157 // makes later adjacent route checks too complicated
17158  Utilities->CallLogPop(259);
17159  return(false);
17160  }
17161  if(Track->IsLCAtHV(21, HLoc, VLoc))
17162  {
17163  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
17164  Utilities->CallLogPop(1910);
17165  return(false);
17166  }
17167 // check if selected a train & disallow if so
17168  if(TrackElement.TrainIDOnElement > -1)
17169  {
17170  if(!Callon)
17171  {
17172  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
17173  }
17174  Utilities->CallLogPop(260);
17175  return(false);
17176  }
17177 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
17178  TPrefDirElement PrefDirElement;
17179  int LockedVectorNumber;
17180 
17181  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
17182  {
17183  if(!Callon)
17184  {
17185  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
17186  }
17187  Utilities->CallLogPop(261);
17188  return(false);
17189  }
17190  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
17191  {
17192  if(!Callon)
17193  {
17194  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
17195  }
17196  Utilities->CallLogPop(262);
17197  return(false);
17198  }
17200 // AdjacentStartRouteNumber = -1;
17201  StartRoutePosition = TrackVectorPosition;
17202 // StartRouteSelectPosition = TrackVectorPosition;
17203 
17204  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17205  TPrefDirElement PrefDirElement2(TrackElement);
17206 
17207  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
17208  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
17209  TPrefDirElement BlankElement;
17210 
17211  PrefDirElement1.ELinkPos = 0;
17212  PrefDirElement1.XLinkPos = 1;
17213  PrefDirElement1.ELink = PrefDirElement1.Link[0];
17214  PrefDirElement1.XLink = PrefDirElement1.Link[1];
17215  if(!(PrefDirElement1.EntryExitNumber()))
17216  {
17217  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
17218  // no need for bridge check as bridge selections not allowed
17219  }
17220  PrefDirElement1.CheckCount = 9;
17221  PrefDirElement2.ELinkPos = 1;
17222  PrefDirElement2.XLinkPos = 0;
17223  PrefDirElement2.ELink = PrefDirElement2.Link[1];
17224  PrefDirElement2.XLink = PrefDirElement2.Link[0];
17225  if(!(PrefDirElement2.EntryExitNumber()))
17226  {
17227  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
17228  }
17229  PrefDirElement2.CheckCount = 9; // both now set
17230 
17231 // set StartElements to the above PrefDirElements
17232  StartElement1 = PrefDirElement1;
17233  StartElement2 = PrefDirElement2;
17234 
17235 // no PrefDir check needed as doesn't need to be in a PrefDir
17236 
17237 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
17239  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17240 
17241  if(RoutePair.first > -1)
17242  {
17243  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
17244  {
17245  if(!Callon)
17246  {
17247  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
17248  }
17249  Utilities->CallLogPop(263);
17250  return(false);
17251  }
17252  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
17253  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
17254  {
17255  if(!Callon)
17256  {
17257  TrainController->StopTTClockMessage(39, "No forward connection from this position");
17258  }
17259  Utilities->CallLogPop(264);
17260  return(false);
17261  }
17262  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
17263  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
17264  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17265  {
17266 // if(!Callon) //dropped at v2.20.2 as wouldn't allow a route to be built from here anyway
17267 // {
17268 // TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
17269 // }
17270 // Utilities->CallLogPop(265);
17271 // return(false);
17272  }
17273  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
17275  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
17276  StartElement2 = BlankElement; // only use the route element
17278  Utilities->CallLogPop(266);
17279  return(true); // all retained values set
17280  }
17281 
17282  else // selection not in an existing route
17283  {
17284 // check if it's adjacent to start of an an existing route,
17285  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17286  {
17287  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
17288  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
17289  {
17290  if(!Callon)
17291  {
17292  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
17293  }
17294  Utilities->CallLogPop(267);
17295  return(false);
17296  }
17297  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
17298  {
17299  if(!Callon)
17300  {
17301  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
17302  }
17303  Utilities->CallLogPop(268);
17304  return(false);
17305  }
17306  }
17307 // check if it's adjacent to end of an an existing route,
17308  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17309  {
17311  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
17312  {
17313  if(!Callon)
17314  {
17315  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
17316  }
17317  Utilities->CallLogPop(269);
17318  return(false);
17319  }
17320  }
17321  // not in a route or adjacent to start or end of a route
17322  // in this case reset all variable values to -1 & CheckCount to 4
17323  StartElement1.ELink = -1;
17324  StartElement1.ELinkPos = -1;
17325  StartElement1.XLink = -1;
17326  StartElement1.XLinkPos = -1;
17327  StartElement1.EXNumber = -1;
17328  StartElement1.CheckCount = 4; //Only covers the fixed values HLoc, VLoc, SpeedTag & TrackVectorPosition
17329  StartElement2 = BlankElement;
17330  SearchVector.push_back(StartElement1);
17331  Utilities->CallLogPop(270);
17332  return(true);
17333  }
17334 }
17335 
17336 // ---------------------------------------------------------------------------
17337 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
17338 
17339 /*
17340  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
17341 
17342  Declare the following integers:-
17343  EndPosition - TrackVectorPosition for the selection;
17344  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
17345  Check if selection is a valid track element and set EndPosition.
17346  Cancel if select original start element, then check that not points, bridge or crossover.
17347  Check & fail if a train is present at the selection.
17348  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
17349  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
17350  No check needed for selection in EveryPrefDir.
17351  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
17352  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
17353  as don't need it if in a route.
17354  Check if selection adj to start or end of a route and disallow.
17355  Fail if select same route as starting route, though should already have failed earlier if this is so.
17356 
17357  If there's a StartSelectionRouteID then StartElement1 will be set to
17358  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
17359  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
17360  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
17361  to add the new route to the AllRoutesVectorPtr.
17362  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
17363  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
17364  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
17365  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
17366  the search vector values and return.
17367  If not returned yet then have failed to find the required element so return false with no message.
17368 
17369 */
17370 
17371 {
17372 // get EndPosition
17373  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
17374  AnsiString(VLoc));
17375  int EndPosition;
17376  int NewFailedPointsTVPos = -1; //added at v2.13.0 for point failures
17377 
17378  TotalSearchCount = 0;
17379  ReqPosRouteID = IDInt(-1); // for not used
17380  TTrackElement TrackElement;
17381  TPrefDirElement BlankElement;
17383 
17384  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
17385  {
17386  Utilities->CallLogPop(271);
17387  return(false);
17388  }
17389 // EndPosition = EndSelectPosition;
17390 // cancel selection if on original start element
17391  if(EndPosition == StartRoutePosition)
17392  {
17393  Utilities->CallLogPop(272);
17394  return(false);
17395  }
17396  if(Track->IsLCAtHV(22, HLoc, VLoc))
17397  {
17398  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
17399  Utilities->CallLogPop(1911);
17400  return(false);
17401  }
17402  if((TrackElement.TrackType == Points) && !Callon)
17403  {
17404  if(!Callon)
17405  {
17406  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
17407  }
17408 // makes later adjacent route checks too complicated
17409  Utilities->CallLogPop(273);
17410  return(false);
17411  }
17412  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
17413  {
17414  if(!Callon)
17415  {
17416  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
17417  }
17418 // makes later adjacent route checks too complicated
17419  Utilities->CallLogPop(1861);
17420  return(false);
17421  }
17422 // check if train on element
17423  if(TrackElement.TrainIDOnElement > -1)
17424  {
17425  if(!Callon)
17426  {
17427  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
17428  }
17429  Utilities->CallLogPop(274);
17430  return(false);
17431  }
17432 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
17433 // check passed)
17434  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
17435  TPrefDirElement EndElement2(TrackElement);
17436 
17437  EndElement1.TrackVectorPosition = EndPosition;
17438  EndElement2.TrackVectorPosition = EndPosition;
17439  EndElement1.ELinkPos = 0;
17440  EndElement1.XLinkPos = 1;
17441  EndElement1.ELink = EndElement1.Link[0];
17442  EndElement1.XLink = EndElement1.Link[1];
17443  if(!(EndElement1.EntryExitNumber()))
17444  {
17445  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
17446  }
17447  EndElement1.CheckCount = 9;
17448  EndElement2.ELinkPos = 1;
17449  EndElement2.XLinkPos = 0;
17450  EndElement2.ELink = EndElement2.Link[1];
17451  EndElement2.XLink = EndElement2.Link[0];
17452  if(!(EndElement2.EntryExitNumber()))
17453  {
17454  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
17455  }
17456  EndElement2.CheckCount = 9; // both now set
17457 
17458 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
17459 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
17460 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
17461 
17462  if(EndElement1.HLoc >= StartElement1.HLoc)
17463  {
17465  SearchLimitHighH = EndElement1.HLoc + 15;
17466  }
17467  else
17468  {
17469  SearchLimitLowH = EndElement1.HLoc - 15;
17471  }
17472  if(EndElement1.VLoc >= StartElement1.VLoc)
17473  {
17475  SearchLimitHighV = EndElement1.VLoc + 15;
17476  }
17477  else
17478  {
17479  SearchLimitLowV = EndElement1.VLoc - 15;
17481  }
17482 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
17483  check & TotalSearchCounts check
17484  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
17485  {
17486  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
17487  Utilities->CallLogPop(1694);
17488  return false;
17489  }
17490 */
17491 // don't need EveryPrefDir check for NonPreferredRoute
17492 
17493 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
17494 // bool InRoute = false;
17496  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
17497 
17498  if(RoutePair.first > -1)
17499  {
17500  if(RoutePair.second != 0) // not first element in existing route so no good
17501  {
17502  if(!Callon)
17503  {
17504  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
17505  }
17506  Utilities->CallLogPop(275);
17507  return(false);
17508  }
17509  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
17510 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
17511  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
17512  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
17513  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
17514  {
17515  if(!Callon)
17516  {
17517  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
17518  }
17519  Utilities->CallLogPop(276);
17520  return(false);
17521  }
17522  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
17523  EndElement2 = BlankElement; // only need the route element
17524  EndPosition = EndElement1.TrackVectorPosition;
17525  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
17526  }
17527 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
17528  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17529  {
17530  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
17531  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
17532 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17533 // && (AdjPosition != StartRoutePosition))
17534  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
17535  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17536  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
17537  {
17538  if(!Callon)
17539  {
17540  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
17541  }
17542  Utilities->CallLogPop(277);
17543  return(false);
17544  }
17545 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
17546 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
17547  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
17548  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
17549  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
17550  (AdjPosition != StartRoutePosition))
17551  {
17552  if(!Callon)
17553  {
17554  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
17555  }
17556  Utilities->CallLogPop(278);
17557  return(false);
17558  }
17559 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
17561  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
17562  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
17563  {
17564  if(!Callon)
17565  {
17566  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
17567  }
17568  Utilities->CallLogPop(279);
17569  return(false);
17570  }
17571  }
17572 
17573 // check for same route as start element
17575  {
17576  if(!Callon)
17577  {
17578  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
17579  }
17580  Utilities->CallLogPop(280);
17581  return(false);
17582  }
17583 // check for a looping route
17584  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
17585  {
17587  {
17588  if(!Callon)
17589  {
17590  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
17591  }
17592  Utilities->CallLogPop(1845);
17593  return(false);
17594  }
17595  }
17596 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
17597 // so search from this element.
17598 
17599  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
17600 
17601  if(StartSelectionRouteID > -1)
17602  {
17603  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, false))
17604  {
17606  if(PointsToBeChanged(0, NewFailedPointsTVPos))
17607  {
17608  if(NewFailedPointsTVPos > -1)
17609  {
17610  TTrackElement TE = Track->TrackElementAt(1494, NewFailedPointsTVPos);
17611  TrainController->StopTTClockMessage(113, "Points at " + TE.ElementID +
17612  " failed during route setting.");
17613  Utilities->CallLogPop(2504);
17614  return(false);
17615  }
17616  PointsChanged = true;
17617  }
17618  Utilities->CallLogPop(281);
17619  return(true);
17620  }
17621  else
17622  {
17623  if(!Callon && !Track->SuppressRouteFailMessage)
17624  {
17626  }
17627  Utilities->CallLogPop(282);
17628  return(false);
17629  }
17630  }
17631  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
17632  // search on the 2 ways out of the element, which has to be a 2-ended element
17633  {
17634 // check if selection adjacent to start element and if so use that
17635  if(SearchVector.at(0).Conn[0] == EndPosition)
17636  {
17637  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID, false))
17638  {
17640  if(PointsToBeChanged(1, NewFailedPointsTVPos))
17641  {
17642  if(NewFailedPointsTVPos > -1)
17643  {
17644  TTrackElement TE = Track->TrackElementAt(1496, NewFailedPointsTVPos);
17645  TrainController->StopTTClockMessage(115, "Points at " + TE.ElementID +
17646  " failed during route setting.");
17647  Utilities->CallLogPop(2506);
17648  return(false);
17649  }
17650  PointsChanged = true;
17651  }
17652  Utilities->CallLogPop(283);
17653  return(true);
17654  }
17655  else
17656  {
17657  if(!Callon && !Track->SuppressRouteFailMessage)
17658  {
17660  }
17661  Utilities->CallLogPop(284);
17662  return(false);
17663  }
17664  }
17665  else if(SearchVector.at(0).Conn[1] == EndPosition)
17666  {
17667  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID, false))
17668  {
17670  if(PointsToBeChanged(2, NewFailedPointsTVPos))
17671  {
17672  if(NewFailedPointsTVPos > -1)
17673  {
17674  TTrackElement TE = Track->TrackElementAt(1498, NewFailedPointsTVPos);
17675  TrainController->StopTTClockMessage(117, "Points at " + TE.ElementID +
17676  " failed during route setting.");
17677  Utilities->CallLogPop(2508);
17678  return(false);
17679  }
17680  PointsChanged = true;
17681  }
17682  Utilities->CallLogPop(285);
17683  return(true);
17684  }
17685  else
17686  {
17687  if(!Callon && !Track->SuppressRouteFailMessage)
17688  {
17690  }
17691  Utilities->CallLogPop(286);
17692  return(false);
17693  }
17694  }
17695  // now start off in the best direction
17696  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
17697 
17698  if(SearchVector.at(0).Config[BestPos] != End)
17699  {
17700  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17701  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID, false))
17702  {
17704  if(PointsToBeChanged(3, NewFailedPointsTVPos))
17705  {
17706  if(NewFailedPointsTVPos > -1)
17707  {
17708  TTrackElement TE = Track->TrackElementAt(1500, NewFailedPointsTVPos);
17709  TrainController->StopTTClockMessage(119, "Points at " + TE.ElementID +
17710  " failed during route setting.");
17711  Utilities->CallLogPop(2510);
17712  return(false);
17713  }
17714  PointsChanged = true;
17715  }
17716  Utilities->CallLogPop(287);
17717  return(true);
17718  }
17719  }
17720  if(SearchVector.at(0).Config[1 - BestPos] != End)
17721  {
17722  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
17723  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID, false))
17724  {
17726  if(PointsToBeChanged(4, NewFailedPointsTVPos))
17727  {
17728  if(NewFailedPointsTVPos > -1)
17729  {
17730  TTrackElement TE = Track->TrackElementAt(1502, NewFailedPointsTVPos);
17731  TrainController->StopTTClockMessage(121, "Points at " + TE.ElementID +
17732  " failed during route setting.");
17733  Utilities->CallLogPop(2512);
17734  return(false);
17735  }
17736  PointsChanged = true;
17737  }
17738  Utilities->CallLogPop(288);
17739  return(true);
17740  }
17741  }
17742  }
17743  if(!Callon && !Track->SuppressRouteFailMessage)
17744  {
17746  }
17747  Utilities->CallLogPop(289);
17748  return(false);
17749 }
17750 
17751 // ---------------------------------------------------------------------------
17752 
17753 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
17754 /*
17755  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
17756  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
17757  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
17758  Keep a count of entries in SearchVector during the current function call, so that this number can be
17759  erased for an unproductive branch search.
17760  First check (within the loop) whether XLink leads to an End & return false if so.
17761  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
17762  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
17763  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
17764  train on element (unless a bridge & train on different track), or if element
17765  fouls an existing diagonal route (except if element is a leading point - these checked later).
17766  Then check if found required element. If so save it & return true.
17767  If not the required element check if buffer or continuation, & if so erase all searchvector
17768  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
17769  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
17770  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
17771  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
17772  When return true have 8 items from CheckCount established, only waiting for EXNumber
17773 */
17774 {
17775  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
17776  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
17777  int VectorCount = 0;
17778 
17779 // check for a fouled diagonal for first element. Added for v1.3.2
17780  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
17781  (CurrentTrackElement.Link[XLinkPos] == 9))
17782  {
17783  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
17784  {
17785  for(int x = 0; x < VectorCount; x++)
17786  {
17787  SearchVector.erase(SearchVector.end() - 1);
17788  }
17789  Utilities->CallLogPop(2044);
17790  return(false);
17791  }
17792  }
17793  while(true)
17794  {
17795  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
17796  {
17797  for(int x = 0; x < VectorCount; x++)
17798  {
17799  SearchVector.erase(SearchVector.end() - 1);
17800  }
17801  Utilities->CallLogPop(1927);
17802  return(false);
17803  }
17804  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
17805  {
17806  for(int x = 0; x < VectorCount; x++)
17807  {
17808  SearchVector.erase(SearchVector.end() - 1);
17809  }
17810  Utilities->CallLogPop(290);
17811  return(false);
17812  }
17813  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
17814  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
17815  TPrefDirElement SearchElement(NextTrackElement);
17816  SearchElement.TrackVectorPosition = NextPosition;
17817  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
17818  SearchElement.ELinkPos = NextELinkPos;
17819  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
17820  int NextXLinkPos;
17821  if(SearchElement.ELinkPos == 0)
17822  {
17823  NextXLinkPos = 1;
17824  }
17825  if(SearchElement.ELinkPos == 1)
17826  {
17827  NextXLinkPos = 0;
17828  }
17829  if(SearchElement.ELinkPos == 2)
17830  {
17831  NextXLinkPos = 3;
17832  }
17833  if(SearchElement.ELinkPos == 3)
17834  {
17835  NextXLinkPos = 2;
17836  }
17837  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
17838  {
17839  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
17840  // but may be buffers, continuation or gap
17841  SearchElement.XLinkPos = NextXLinkPos;
17842  }
17843 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
17844 // can't set XLink or XLinkPos yet if the element is a leading point.
17845 
17846 /* check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
17847  drop this as time-consuming, and RouteSearchLimit will stop the search if on a loop <--NO, need to keep in the case of crossovers as can reach
17848  element on opposite track and still find the required end point - causes error when adding to the Route"MultiMap (happened by chance when
17849  developing non-station named elements on points & crossovers). BUT need to speed up, don't use brute force search through all searchvector.
17850 
17851  just test 4-track elements & fail for crossover, points or bridge on same track, if 2-track then looping and searchlimit will stop - changed at v2.18.0
17852 */
17853  if((SearchElement.TrackType == Crossover) || (SearchElement.TrackType == Points))
17854  {
17855  for(unsigned int x = 0; x < SearchVector.size(); x++)
17856  {
17857  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc)) //same element
17858  {
17859  for(int x = 0; x < VectorCount; x++)
17860  {
17861  SearchVector.erase(SearchVector.end() - 1);
17862  }
17863  Utilities->CallLogPop(2655);
17864  return(false);
17865  }
17866  }
17867  }
17868  else if(SearchElement.TrackType == Bridge)
17869  {
17870  for(unsigned int x = 0; x < SearchVector.size(); x++)
17871  {
17872  if((SearchVector.at(x).HLoc == SearchElement.HLoc) && (SearchVector.at(x).VLoc == SearchElement.VLoc) && //same element & same ELink
17873  (SearchElement.ELink == SearchVector.at(x).ELink))
17874  {
17875  for(int x = 0; x < VectorCount; x++)
17876  {
17877  SearchVector.erase(SearchVector.end() - 1);
17878  }
17879  Utilities->CallLogPop(2656);
17880  return(false);
17881  }
17882  }
17883  }
17884 
17885 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
17886  TAllRoutes::TRouteElementPair SecondPair;
17888  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
17889  if(RoutePair.first > -1)
17890  {
17891  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
17892  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
17893  RoutePair.second).ELinkPos)))
17894  {
17895  // still OK if start of an expected route
17896  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
17897  {
17898  for(int x = 0; x < VectorCount; x++)
17899  {
17900  SearchVector.erase(SearchVector.end() - 1);
17901  }
17902  Utilities->CallLogPop(292);
17903  return(false); // only allow for start of an expected route
17904  }
17905  }
17906  }
17907  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
17908  {
17909  // OK if it's a bridge & routes on different tracks
17910  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
17911  SecondPair.second).ELinkPos)))
17912  {
17913  // still OK if start of an expected route
17914  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
17915  {
17916  for(int x = 0; x < VectorCount; x++)
17917  {
17918  SearchVector.erase(SearchVector.end() - 1);
17919  }
17920  Utilities->CallLogPop(293);
17921  return(false); // only allow for start of an expected route
17922  }
17923  }
17924  }
17925 // check if a train on element, unless a bridge & train on different track
17926 // OK of same train as start element - no, drop this
17927 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
17928  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
17929  {
17930  for(int x = 0; x < VectorCount; x++)
17931  {
17932  SearchVector.erase(SearchVector.end() - 1);
17933  }
17934  Utilities->CallLogPop(294);
17935  return(false);
17936  }
17937  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
17938  {
17939  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 > -1))
17940  {
17941  for(int x = 0; x < VectorCount; x++)
17942  {
17943  SearchVector.erase(SearchVector.end() - 1);
17944  }
17945  Utilities->CallLogPop(295);
17946  return(false);
17947  }
17948  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23 > -1))
17949  {
17950  for(int x = 0; x < VectorCount; x++)
17951  {
17952  SearchVector.erase(SearchVector.end() - 1);
17953  }
17954  Utilities->CallLogPop(296);
17955  return(false);
17956  }
17957  }
17958 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
17959  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
17960  {
17961  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
17962  {
17963  for(int x = 0; x < VectorCount; x++)
17964  {
17965  SearchVector.erase(SearchVector.end() - 1);
17966  }
17967  Utilities->CallLogPop(297);
17968  return(false);
17969  }
17970  }
17971 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
17972 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
17973 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
17975  {
17976  for(int x = 0; x < VectorCount; x++)
17977  {
17978  SearchVector.erase(SearchVector.end() - 1);
17979  }
17980  Utilities->CallLogPop(1689);
17981  return(false);
17982  }
17983 // check if found it
17984  if(SearchElement.TrackVectorPosition == RequiredPosition)
17985  {
17986  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
17987  {
17988  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
17989  {
17990  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
17991  }
17992  else
17993  {
17994  SearchElement.XLinkPos = 1;
17995  }
17996 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
17997  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
17998  }
17999  SearchVector.push_back(SearchElement);
18000  VectorCount++; // not really needed but include for tidyness
18001  TotalSearchCount++;
18002  if(!RecursiveCall && SignalHasFailed(3)) //added at v2.13.0
18003  {
18004  for(int x = 0; x < VectorCount; x++)
18005  {
18006  SearchVector.erase(SearchVector.end() - 1);
18007  }
18008  Utilities->CallLogPop(2525);
18009  return(false);
18010  }
18011  Utilities->CallLogPop(298);
18012  return(true);
18013  }
18014 // Not the required element - check if a buffer or continuation
18015  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
18016  {
18017  for(int x = 0; x < VectorCount; x++)
18018  {
18019  SearchVector.erase(SearchVector.end() - 1);
18020  }
18021  Utilities->CallLogPop(299);
18022  return(false);
18023  }
18024 // check if SearchVector exceeds a size of RouteSearchLimitOneLeg (300)
18026  {
18027  for(int x = 0; x < VectorCount; x++)
18028  {
18029  SearchVector.erase(SearchVector.end() - 1);
18030  }
18031  Utilities->CallLogPop(1421);
18032  return(false);
18033  }
18034 //deal with failed points, added at v2.13.0
18035  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && Track->TrackElementAt(1524, SearchElement.TrackVectorPosition).Failed) //leading entry
18036  {
18037  if(Track->TrackElementAt(1525, SearchElement.TrackVectorPosition).Attribute == 0)
18038  {
18039  SearchElement.XLinkPos = 1;
18040  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
18041  }
18042  else
18043  {
18044  SearchElement.XLinkPos = 3;
18045  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos];
18046  }
18047  }
18048  else if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Trail) && Track->TrackElementAt(1526, SearchElement.TrackVectorPosition).Failed) //trailing entry
18049  {
18050  if((Track->TrackElementAt(1527, SearchElement.TrackVectorPosition).Attribute == 0) && (SearchElement.ELinkPos == 3)) //can't go any further
18051  {
18052  for(int x = 0; x < VectorCount; x++)
18053  {
18054  SearchVector.erase(SearchVector.end() - 1);
18055  }
18056  Utilities->CallLogPop(2533);
18057  return(false);
18058  }
18059  if((Track->TrackElementAt(1528, SearchElement.TrackVectorPosition).Attribute == 1) && (SearchElement.ELinkPos == 1)) //can't go any further
18060  {
18061  for(int x = 0; x < VectorCount; x++)
18062  {
18063  SearchVector.erase(SearchVector.end() - 1);
18064  }
18065  Utilities->CallLogPop(2534);
18066  return(false);
18067  }
18068  }
18069 
18070 // check if reached a non-failed leading point
18071  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead) && !SearchElement.Failed)
18072  { //added !Failed condition at v2.13.0 to exclude failed points
18073 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
18074  int SearchPos1 = SearchElement.Attribute + 1;
18075  int SearchPos2;
18076  if(SearchPos1 == 2)
18077  {
18078  SearchPos1++;
18079  }
18080  if(SearchPos1 == 1)
18081  {
18082  SearchPos2 = 3;
18083  }
18084  else
18085  {
18086  SearchPos2 = 1;
18087  }
18088 // push element with XLink set to position [SearchPos1]
18089  SearchElement.XLink = SearchElement.Link[SearchPos1];
18090  SearchElement.XLinkPos = SearchPos1;
18091 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
18092  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
18093  {
18094  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
18095  {
18096  for(int x = 0; x < VectorCount; x++)
18097  {
18098  SearchVector.erase(SearchVector.end() - 1);
18099  }
18100  Utilities->CallLogPop(300);
18101  return(false);
18102  }
18103  }
18104  SearchVector.push_back(SearchElement);
18105  VectorCount++;
18106  TotalSearchCount++;
18107 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
18108 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
18109 // recursive search as has to be a TTrackElement for non-preferred route searches
18110  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID, true))
18111  {
18112  if(!RecursiveCall && SignalHasFailed(4)) //added at v2.13.0
18113  {
18114  for(int x = 0; x < VectorCount; x++)
18115  {
18116  SearchVector.erase(SearchVector.end() - 1);
18117  }
18118  Utilities->CallLogPop(2526);
18119  return(false);
18120  }
18121  Utilities->CallLogPop(301);
18122  return(true);
18123  }
18124  else
18125  {
18126 // remove leading point with XLinkPos [SearchPos1]
18127  SearchVector.erase(SearchVector.end() - 1);
18128  VectorCount--;
18129 // push element with XLink set to position [SearchPos2]
18130  SearchElement.XLink = SearchElement.Link[SearchPos2];
18131  SearchElement.XLinkPos = SearchPos2;
18132 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
18133  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
18134  {
18135  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
18136  {
18137  for(int x = 0; x < VectorCount; x++)
18138  {
18139  SearchVector.erase(SearchVector.end() - 1);
18140  }
18141  Utilities->CallLogPop(302);
18142  return(false);
18143  }
18144  }
18145  SearchVector.push_back(SearchElement);
18146  VectorCount++;
18147  TotalSearchCount++;
18148 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
18149  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID, true))
18150  {
18151  if(!RecursiveCall && SignalHasFailed(5)) //added at v2.13.0
18152  {
18153  for(int x = 0; x < VectorCount; x++)
18154  {
18155  SearchVector.erase(SearchVector.end() - 1);
18156  }
18157  Utilities->CallLogPop(2527);
18158  return(false);
18159  }
18160  Utilities->CallLogPop(303);
18161  return(true);
18162  }
18163  else
18164  {
18165  for(int x = 0; x < VectorCount; x++)
18166  {
18167  SearchVector.erase(SearchVector.end() - 1);
18168  }
18169  Utilities->CallLogPop(304);
18170  return(false);
18171  }
18172  }
18173  } // if leading point
18174 
18175 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
18176 // ready for next element on route
18177  SearchVector.push_back(SearchElement);
18178  VectorCount++;
18179  TotalSearchCount++;
18180  CurrentTrackElement = SearchElement;
18181  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
18182  } // while(true)
18183 }
18184 
18185 // ---------------------------------------------------------------------------
18186 
18188 
18189 /*
18190  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
18191  having all values set (since not necessarily on PrefDirs).
18192  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
18193  (if it was the start), so these are checked first and set if necessary. All elements now have
18194  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
18195  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
18196  to set the route colour and direction graphics.
18197 */
18198 
18199 {
18200  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
18201  if(SearchVector.size() == 0)
18202  {
18203  throw Exception("Error, SearchVector empty");
18204  }
18205 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
18206 // hence need to examine and update it if necessary
18207  TPrefDirElement SecondElement;
18208 
18209  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
18210  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
18211  // need above check or SecondElement will fail
18212  {
18213  SecondElement = SearchVector.at(1);
18214  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
18215  for(int x = 0; x < 4; x++)
18216  {
18217  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
18218  {
18219  if(SearchVector.at(0).XLink == -1) // i.e. not set
18220  {
18221  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
18222  SearchVector.at(0).XLinkPos = x;
18223  }
18224  int ELinkPos;
18225  if(SearchVector.at(0).XLinkPos == 0)
18226  {
18227  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
18228  }
18229  // linked to 1st searchvector element, & if XLink was set then x may not correspond
18230  if(SearchVector.at(0).XLinkPos == 1)
18231  {
18232  ELinkPos = 0;
18233  }
18234  if(SearchVector.at(0).XLinkPos == 2)
18235  {
18236  ELinkPos = 3;
18237  }
18238  if(SearchVector.at(0).XLinkPos == 3)
18239  {
18240  ELinkPos = 2;
18241  }
18242  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
18243  {
18244  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
18245  SearchVector.at(0).ELinkPos = ELinkPos;
18246  }
18247  break; // no point going any further
18248  }
18249  }
18250  }
18251  for(unsigned int x = 0; x < SearchVector.size(); x++)
18252  {
18253  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
18254 // set EXNumber
18255  if(!(SearchVector.at(x).EntryExitNumber()))
18256  {
18257  throw Exception("Error in EntryExitNumber 3");
18258  }
18259  SearchVector.at(x).CheckCount++;
18260 // all values now incorporated
18261  }
18262 
18263  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
18264 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
18265 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
18266  Utilities->CallLogPop(305);
18267 }
18268 
18269 // ---------------------------------------------------------------------------
18270 
18272 
18273 /*
18274  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
18275  AutoSigsRoute.
18276  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
18277  beginning or the end.
18278  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
18279  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
18280  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
18281  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
18282  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
18283  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
18284  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
18285 
18286  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
18287  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
18288  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
18289  route at the start.
18290 
18291  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
18292  for the new route and return.
18293 */
18294 
18295 {
18296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
18297  AnsiString(ReqPosRouteID.GetInt()));
18298  if(SearchVector.size() < 1)
18299  {
18300  Utilities->CallLogPop(306);
18301  return;
18302  }
18303  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
18304  if(!ValidatePrefDir(6))
18305  {
18306  Utilities->CallLogPop(307);
18307  return;
18308  }
18309  TAllRoutes::TLockedRouteClass LockedRouteObject;
18310 
18312  unsigned int TruncatePrefDirPosition = 0;
18313 
18314  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
18315 /* if have ReqPosRouteID:
18316  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
18317  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
18318  then enter the new route into the AllRoutesVector
18319 */
18320  {
18322  {
18323  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
18324  x++) // start at 1 as first element already in SearchVector
18325  {
18327  }
18328  // note that route numbers in map adjusted when ReqPos route cleared
18330  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
18331  // set during ClearRouteDuringRouteBuildingAt)
18333  {
18336  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
18337  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
18338  }
18339  }
18341  {
18342  SearchVector.pop_back();
18343  }
18344  }
18345  if(StartSelectionRouteID > -1)
18346 /* if have StartSelectionRouteID:
18347  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
18348  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18349 */
18350  {
18352  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
18353  {
18355  {
18356  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
18357  for(unsigned int x = 0; x < SearchVector.size(); x++)
18358  {
18360  RouteNumber, GetFixedSearchElementAt(7, x));
18361  // find & store locked route truncate position in PrefDirVector for later use
18363  {
18364  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteRearTrackVectorPosition))
18365  {
18366  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
18367  }
18368  }
18369  }
18371  {
18372  throw Exception("Failed to validate extended route for nonpreferred route");
18373  }
18376  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
18377  // now add the reinstated locked route if required and set signals accordingly
18378  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
18379  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
18380  // that I haven't thought of
18382  {
18383  LockedRouteObject.RouteNumber = RouteNumber;
18384  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
18385  // now reset the signals for the locked route
18386  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
18387  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
18388  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
18389  {
18390  // return all signals to red in route section to be truncated
18391  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
18392  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
18393  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
18394  {
18395  TrackElement.Attribute = 0;
18396  Track->PlotSignal(11, TrackElement, Display);
18397  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
18398  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
18399  }
18400  }
18401  }
18402  AllRoutes->CheckMapAndRoutes(3); // test
18403  Utilities->CallLogPop(308);
18404  return;
18405  }
18406  }
18407  else
18408  {
18410  }
18411 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
18412 // hence nothing to do here
18413  }
18414  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
18415  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
18416  {
18417  throw Exception("Failed to validate single route for nonpreferred route");
18418  }
18419  AllRoutes->StoreOneRoute(2, this);
18420  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
18421  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
18422  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
18423  AllRoutes->CheckMapAndRoutes(4); // test
18424  Utilities->CallLogPop(309);
18425 }
18426 
18427 // ---------------------------------------------------------------------------
18428 
18429 void TOneRoute::SetRoutePoints(int Caller) const
18430 /*
18431  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
18432  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
18433  when they were created.
18434 */
18435 {
18436  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
18437  if(!PrefDirVector.empty())
18438  {
18439  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18440  {
18441  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) //1=straight trailing
18442  {
18443  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
18444  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
18445  }
18446  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) //3=diverging trailing
18447  {
18448  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
18449  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
18450  }
18451  }
18452  }
18453  Utilities->CallLogPop(327);
18454 }
18455 
18456 // ---------------------------------------------------------------------------
18457 
18458 void TOneRoute::SetRouteSignals(int Caller) const
18459 // Used for new train additions in AddTrain and in route setting, major changes at v2.17.0
18460 
18461 {
18462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
18463  if(!PrefDirVector.empty())
18464  {
18465  int RouteNumber;
18466  int Attribute = 0;
18467  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
18468  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
18469  if(RouteType != TAllRoutes::NoRoute)
18470  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
18471  {
18472  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
18473  }
18474  }
18475  Utilities->CallLogPop(1720);
18476 }
18477 
18478 // ---------------------------------------------------------------------------
18479 
18480 bool TOneRoute::PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
18481 {
18482  //true if at any point in SearchVector points have to be changed,
18483  //changed to give every point to be changed in route to have a chance of failure, but if one fails then don't look any further
18484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
18485  NewFailedPointsTVPos = -1; //default value for no new failure
18486  bool PointsChanged = false;
18487  if(!SearchVector.empty())
18488  {
18489  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
18490  {
18491  TTrackElement &TE = Track->TrackElementAt(1504, SearchPtr->TrackVectorPosition);
18492  //check for an existing failed point where needs to change to make the route
18493  int Attr = TE.Attribute;
18494  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=want to go straight
18495  {
18496  if(Attr == 1) //currently set to diverge
18497  {
18498  //here add new failure possibility at v2.13.0
18499  if(Utilities->FailureMode != FNil)
18500  {
18501  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18502  {
18504  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18505  IFE.TVPos = NewFailedPointsTVPos;
18506  TE.Failed = true;
18507  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18509  TE.SpeedLimit01 = 10; //values while failed
18510  TE.SpeedLimit23 = 10;
18511  Display->WarningLog(13, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18512  PerfLogForm->PerformanceLog(36, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18513  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18514  //set repair time, random value in minutes between 10 and 179
18515  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
18516  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18517  IFE.RepairTime = RepairTime;
18519  Track->FailedPointsVector.push_back(IFE);
18520  Utilities->CallLogPop(1717);
18521  return(true); //return so only allow one failure per route
18522  }
18523  }
18524  PointsChanged = true; //this is used for setting the flash time
18525  }
18526  }
18527  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=want to diverge
18528  {
18529  if(Attr == 0) //currently set to go straight
18530  {
18531  //here add failure possibility at v2.13.0
18532  if(Utilities->FailureMode != FNil)
18533  {
18534  if((random(Utilities->PointChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice, but if failed should already have been picked up during search
18535  {
18537  NewFailedPointsTVPos = SearchPtr->TrackVectorPosition;
18538  IFE.TVPos = NewFailedPointsTVPos;
18539  TE.Failed= true;
18540  TE.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01 = TE.SpeedLimit01; //store these values temporarily, points aren't bridges so can use these
18542  TE.SpeedLimit01 = 10; //values while failed
18543  TE.SpeedLimit23 = 10;
18544  Display->WarningLog(14, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Points failed at " + TE.ElementID);
18545  PerfLogForm->PerformanceLog(37, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Points failed at " + TE.ElementID);
18546  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
18547  //set repair time, random value in minutes between 10 and 179
18548  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime);
18549  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
18550  IFE.RepairTime = RepairTime;
18552  Track->FailedPointsVector.push_back(IFE);
18553  Utilities->CallLogPop(1718);
18554  return(true); //only allow one failure per route
18555  }
18556  }
18557  PointsChanged = true;
18558  }
18559  }
18560  }
18561  }
18562  Utilities->CallLogPop(1719);
18563  return(PointsChanged);
18564 }
18565 
18566 // ---------------------------------------------------------------------------
18567 
18568 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
18569 /* //added StartPos at v2.17.0 so it starts in the current route
18570 
18571  Only called by SetRearwardsSignalsReturnFalseForTrainInRear
18572 
18573  Works forward through the route from & including StartPos until finds:-
18574  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18575  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
18576  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
18577  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18578  (e) forward-facing non-ground signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (non-ground sig condition added at v2.14.0)
18579  (e1) forward-facing ground signal with attribute 0 - Attribute = ground signal attribute + 1 (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18580  (e2) forward-facing ground signal with attribute > 0 - Attribute = ground signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true; (ground sig condition added at v2.14.0)
18581  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
18582  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
18583 */
18584 {
18585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
18586  Attribute = 0;
18587  NextForwardLinkedRouteNumber = -1;
18588  for(unsigned int x = StartPos; x < PrefDirSize(); x++)
18589  {
18590  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
18591  if(PrefDirVector.at(x).TrackType == Bridge)
18592  {
18593  if(PrefDirVector.at(x).XLinkPos < 2)
18594  {
18595  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18596  }
18597  else
18598  {
18599  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18600  }
18601  }
18602  if(TrainID != -1)
18603  {
18604  Utilities->CallLogPop(328); //attribute still 0
18605  return(true);
18606  }
18607  if(PrefDirVector.at(x).TrackType == Buffers)
18608  {
18609  Attribute = 1;
18610  Utilities->CallLogPop(329);
18611  return(true);
18612  }
18613  if(PrefDirVector.at(x).TrackType == Continuation)
18614  {
18615  Attribute = 3;
18616  Utilities->CallLogPop(330);
18617  return(true);
18618  }
18619  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18620  {
18621  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
18622  {
18623  Attribute = 0;
18624  Utilities->CallLogPop(1950);
18625  return(true);
18626  }
18627  }
18628  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
18629  {
18630  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute; //added at v2.14.0
18631  if((PrefDirVector.at(x).SigAspect != TTrackElement::GroundSignal) || (Attribute == 0))//added at v2.14.0
18632  {
18633  Attribute++;
18634  }
18635  if(Attribute > 3)
18636  {
18637  Attribute = 3;
18638  }
18639  Utilities->CallLogPop(331);
18640  return(true);
18641  }
18642  if(x == PrefDirSize() - 1) //end element and not signal, buffer, continuation or LC, and no train on element
18643  {
18644  TPrefDirElement LastElement = GetFixedPrefDirElementAt(268, x);
18645  NextForwardLinkedRouteNumber = -1;
18646  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(42, Track->TrackElementAt(1579, LastElement.TrackVectorPosition).Conn[LastElement.XLinkPos], Track->TrackElementAt(1580, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos], NextForwardLinkedRouteNumber);
18647 //the above returns a route (or no route) but LinkPos can be entry or exit, so still need to know it's the entry link for the follow-on route to be valid
18648  if(!(RouteType == TAllRoutes::NoRoute)) //probably a forward route but still need to check if it's linked
18649  {
18650  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(227, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(269, 0); //0 is start position
18651  if(NewRoutePDE.ELinkPos == Track->TrackElementAt(1581, LastElement.TrackVectorPosition).ConnLinkPos[LastElement.XLinkPos]) //if it's not then route not linked so there's no forward route
18652  {
18653  Attribute = 0;
18654  Utilities->CallLogPop(332);
18655  return(false);
18656  }
18657  //else there is no forward route, so return true with attribute still 0
18658  }
18659  //else there is no forward route, so return true with attribute still 0
18660  }
18661  }
18662  Utilities->CallLogPop(333); //
18663  return(true);
18664 }
18665 
18666 // ---------------------------------------------------------------------------
18667 
18668 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
18669 /* Major changes at v2.17.0
18670  This function is only called by TAllRoutes::SetAllRearwardsSignals.
18671 
18672  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18673  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18674  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
18675  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
18676  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
18677  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
18678  or (c) truncating a route.
18679 
18680  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18681  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
18682  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
18683  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
18684  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
18685  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
18686  the function returns true.
18687 
18688  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
18689  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18690 */
18691 {
18692  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrainInRear," + AnsiString(Attribute) + "," +
18693  AnsiString(PrefDirVectorStartPosition));
18694  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
18695  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
18696 // if no train or closed LC between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
18697 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
18698 
18699  if(!PrefDirVector.empty())
18700  {
18701  if(!SkipForwardLook)
18702  {
18703  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
18704  {
18705  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18706  if(PrefDirPtr->TrackType == Bridge)
18707  {
18708  if(PrefDirPtr->XLinkPos < 2)
18709  {
18710  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18711  }
18712  else
18713  {
18714  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18715  }
18716  }
18717  if(TrainID != -1)
18718  {
18719  SkipForwardLook = true;
18720  break;
18721  }
18722  }
18723  }
18724 
18726  {
18727  SkipForwardLook = true;
18728  }
18729 
18730  int NextForwardLinkedRouteNumber = -1;
18731  if((unsigned int)PrefDirVectorStartPosition == PrefDirSize() - 1) //end element of route
18732  {
18733  TPrefDirElement PDE = GetFixedPrefDirElementAt(267, PrefDirVectorStartPosition);
18735 //the above returns a route (or no route) but LinkPos can be entry or exit, and need to know it's the entry link for the follow-on route to be valid
18736  if(RouteType == TAllRoutes::NoRoute)
18737  {
18738  SkipForwardLook = true; //if there's no linked forward route then skip
18739  if(PrefDirVector.back().TrackType == Buffers)
18740  {
18741  Attribute = 1; // treat buffer as red signal
18742  }
18743  if(PrefDirVector.back().TrackType == Continuation)
18744  { //check if timing out and no train between 1st signal and continuation and if so don't change attribute
18745  bool SetAttributeTo3 = true;
18748  {
18749  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
18750  AutoSigVectorIT++)
18751  {
18752  if(!AllRoutes->AllRoutesVector.empty())
18753  {
18754  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
18755  {
18756  SetAttributeTo3 = false;
18757  Attribute = AutoSigVectorIT->AccessNumber;
18758  break;
18759  }
18760  }
18761  }
18762  }
18763  if(SetAttributeTo3)
18764  {
18765  Attribute = 3; // treat continuation as a green signal
18766  }
18767  }
18768  }
18769  else //startpos still on end element and there is probably a forward route
18770  {
18771  TPrefDirElement NewRoutePDE = AllRoutes->GetFixedRouteAt(228, NextForwardLinkedRouteNumber).GetFixedPrefDirElementAt(270, 0); //0 is start position
18772  if(NewRoutePDE.ELinkPos != Track->TrackElementAt(1584, PDE.TrackVectorPosition).ConnLinkPos[PDE.XLinkPos]) //if it's not then route not linked so there's no forward route
18773  {
18774  SkipForwardLook = true; //if there's no linked forward route then skip
18775  if(PrefDirVector.back().TrackType == Buffers)
18776  {
18777  Attribute = 1; // treat buffer as red signal
18778  }
18779  if(PrefDirVector.back().TrackType == Continuation)
18780  {
18781  Attribute = 3; // treat continuation as a green signal
18782  }
18783  }
18784  //else there is a forward route, so just continue to examine it below unless SkipForwardLook is true
18785  }
18786  }
18787 
18788  if(!SkipForwardLook)
18789  {
18790  //start from element in front of PrefDirVectorStartPosition, which may be in same or next forward route (if there isn't one then
18791  //SkipForwardLook will be true - see above)
18792  int StartPos;
18793  if((unsigned int)PrefDirVectorStartPosition < (PrefDirSize() - 1))
18794  {
18795  StartPos = PrefDirVectorStartPosition + 1;
18796  }
18797  else
18798  {
18799  StartPos = 0; //start of next forward route
18800  }
18801  if(StartPos > 0) //starting in this route
18802  {
18803  if(!FindForwardTargetSignalAttribute(2, NextForwardLinkedRouteNumber, Attribute, StartPos))// returns false for having to link to next route to continue search
18804  {
18805  StartPos = 0; //reset to 0 for next route
18806  while(!AllRoutes->GetFixedRouteAt(229, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(3, NextForwardLinkedRouteNumber, Attribute, StartPos))
18807  {
18808  continue;
18809  }
18810  }
18811  }
18812  else //starting in next forward route
18813  {
18814  while(!AllRoutes->GetFixedRouteAt(230, NextForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(4, NextForwardLinkedRouteNumber, Attribute, StartPos))
18815  {
18816  continue;
18817  }
18818  }
18819  }
18820 
18821  //now have target attribute (as supplied or modified in forward look) so look backwards to set signals
18822  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
18823  {
18824  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
18825  if(PrefDirPtr->TrackType == Bridge)
18826  {
18827  if(PrefDirPtr->XLinkPos < 2)
18828  {
18829  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
18830  }
18831  else
18832  {
18833  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
18834  }
18835  }
18836  if(TrainID != -1)
18837  {
18838  Utilities->CallLogPop(334);
18839  return(false);
18840  }
18841  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
18842  // the attribute to 0 so first signal behind the LC is red
18843  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18844  {
18845  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
18846  {
18847  Attribute = 0;
18848  }
18849  }
18850 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
18851 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
18852  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
18853  {
18854  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
18855  PrefDirPtr->PrefDirRoute)
18856  {
18857 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
18858 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
18859  int LockedVecNum = 0; //not used
18860  TPrefDirElement DummyPrefDir; //not used
18861  bool KeepAttributeAt0ForLockedRoute = false;
18862  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
18863  LockedVecNum))
18864  {
18865  Attribute = 0;
18866  KeepAttributeAt0ForLockedRoute = true;
18867  }
18868 //end of v2.9.2 addition
18869 
18870 //v2.14.0 addition to avoid incrementing attribute for forward ground signals, ground sig itself takes attribute of forward signal + 1
18871  bool NotGroundSignal = false;
18872  if(PrefDirPtr->SigAspect != TTrackElement::GroundSignal)
18873  {
18874  NotGroundSignal = true;
18875  }
18876 
18877  if(Track->TrackElementAt(1529, PrefDirPtr->TrackVectorPosition).Failed) //addition at v2.13.0 for signal failures
18878  {
18879  Attribute = 0; //stays at 0
18880  }
18881 
18882  if(Attribute < 3)
18883  {
18884  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
18885  }
18886  else
18887  {
18888  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
18889  }
18890  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
18891  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
18892  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
18893  {
18894  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18895  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
18896  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
18897  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
18898  }
18899  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute && (NotGroundSignal || (Attribute == 0))) //NotGroundSignal... added at v2.14.0 (see above)
18900  { //if groundsignal attrib is 0 then do need to increment
18901  Attribute++; //this is for the next signal rearwards, not the current one
18902  }
18903 // Display->Update(); // update after recent plots //dropped at v2.14.0 to avoid signals on routes showing before loaded session, relaced by the below
18904  AllRoutes->RebuildRailwayFlag = true; //added at v2.14.0 to force a rebuild in place of the above
18905  }
18906  }
18907  }
18908  }
18909  Utilities->CallLogPop(335);
18910  return(true);
18911 }
18912 
18913 // ---------------------------------------------------------------------------
18914 
18915 void TOneRoute::TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
18916 /*
18917  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
18918  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
18919  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
18920  Selection invalid if select a bridge; trying to leave a single element; last element to be left
18921  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
18922  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
18923  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
18924  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
18925 
18926  Note that this function was heavily modified at v2.21.0 when clicking a signal truncates to next signal - with additional conditions, see click table below
18927 */
18928 {
18929  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TruncateRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18930  "," + AnsiString((short)PrefDirRoute));
18931  bool ElementInRoute = false;
18932  TOneRoute ReinstatementRoute = *this; //added at v2.21.0 for truncation to next signal
18933  int LastElementToBeTruncated = -1; //added at v2.21.0 for truncation to next signal
18934  bool MovingTrainOccupyingRoute = false;
18935  unsigned int TruncatePDElementPos; //the selected PD position to truncate to & include in the truncation (could be from the back or the front)//added at v2.15.0
18936  enum {NoTruncate, BackTruncate, FrontTruncate, NextSignalTruncate, FullTruncate} TruncateType;
18937  TruncateType = NoTruncate;
18938  AllRoutes->RouteTruncateFlag = false;
18939  //first check the truncate point is in a route
18940  for(unsigned int b = 0; b < PrefDirSize(); b++)
18941  {
18942  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
18943  {
18944  TruncatePDElementPos = b;
18945  ElementInRoute = true;
18946  break;
18947  }
18948  }
18949  if(!ElementInRoute)
18950  {
18951  ReturnFlag = NotInRoute;
18952  Utilities->CallLogPop(336);
18953  return;
18954  }
18955 
18956  //click table
18957  //click route sig position result
18958 
18959  //element after signal any mid-route BackTruncate
18960  //element after signal any start of route Not allowed (message given saying would leave single element)
18961  //element before signal any mid-route FrontTruncate
18962  //element before signal any end of route Not allowed (message given saying would leave single element)
18963  //signal any mid-route & signal after that isn't the end NextSignalTruncate
18964  //signal any mid-route & signal after that is the end BackTruncate
18965  //signal any mid-route & no signal after BackTruncate
18966  //signal green or blue end of route Invalid element message
18967  //signal red end of route Erases last element only
18968  //start of route (signal or not)any n/a FullTruncate (never need to clear from entry to next signal as can add a signal)
18969  //end of route (not signal) green or blue n/a Give invalid element message
18970  //end of route (any element) red n/a Erases last element only
18971 
18972  //now find whether back, front, nextsignal (added at v2.21.0) or full truncate //added at v2.15.0, backtrucate = from truncate position to the end of the route (i.e. the original truncate function)
18973  if(TruncatePDElementPos < (PrefDirSize() - 1)) //if last position then can't be a front truncate as that requires a signal after the truncate point
18974  {
18975  if(TruncatePDElementPos == 0) //start of route
18976  {
18977  TruncateType = FullTruncate;
18978  AllRoutes->RouteTruncateFlag = true; //Added at v2.15.1: Set for all route truncate types, used in SetAllRearwardsSignals to prevent a forward look.
18979  //Without this, if a non-autosigs route is in front of an autosigs route and runs into buffers or a
18980  //continuation, and the non-autosigs route is truncated back to the autosigs route (i.e. a full
18981  //truncate for that route), the last signal in the autosigs route doesn't change to red.
18982  }
18983  else
18984  {
18985  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1); //+1 will exist becaue of first condition
18986  if(TempElement.Config[TempElement.XLinkPos] == Signal)
18987  {
18988  TruncateType = FrontTruncate;
18989  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point //added after v2.23.0 because of Fly California/Silicon Airways
18990  } //bug report via discord (ticket #87) where front truncated segment of a green route following a blue route & blue route end signal stayed green
18991  else //here could be back or next signal truncate, next sig truncate if truncate pos is a signal and there's a signal after that isn't the end of the route
18992  {
18993  TempElement = PrefDirVector.at(TruncatePDElementPos);
18994  if(TempElement.Config[TempElement.XLinkPos] == Signal) //possibly next sig truncate
18995  {
18996  TruncatePDElementPos++; //need to add one as in all cases don't want to truncate the signal itself, also there esists a +1 because of the first condition
18997  //now look forwards to next signal, if it's the end or no signal then it's BackTruncate
18998  int b;
18999  for(b = int(TruncatePDElementPos); b < int(PrefDirSize()); b++)
19000  {
19001  TempElement = PrefDirVector.at(b);
19002  if((TempElement.Config[TempElement.XLinkPos] == Signal) && (b < int(PrefDirSize() - 1))) //if met then it's a mid-route signal
19003  {
19004  TruncateType = NextSignalTruncate;
19005  AllRoutes->RouteTruncateFlag = true; //to set signals properly rearwards of truncate point - relies on rearwards sig setting before re-instatement route sig setting
19006  break; //re-instatement route sig setting
19007  }
19008  }
19009  if(b == int(PrefDirSize())) //i.e. haven't found a mid-route signal
19010  {
19011  TruncateType = BackTruncate;
19012  AllRoutes->RouteTruncateFlag = true;
19013  }
19014  }
19015  else
19016  {
19017  TruncateType = BackTruncate;
19018  AllRoutes->RouteTruncateFlag = true;
19019  }
19020  }
19021  }
19022  }
19023  else // == PrefDirSize() - 1, i.e. end of route
19024  {
19025  TruncateType = BackTruncate;
19026  AllRoutes->RouteTruncateFlag = true;
19027  }
19028 
19029 // it is in the route so continue, first look for a train or a flashing level crossing in the part to be removed
19030 
19031  if(TruncateType == BackTruncate) //added at v2.15.0
19032  {
19033  for(int b = PrefDirSize() - 1; b >= 0; b--)
19034  {
19035  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19036  if(PrefDirVector.at(b).TrackType == Bridge)
19037  {
19038  if(PrefDirVector.at(b).XLinkPos < 2)
19039  {
19040  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19041  }
19042  else
19043  {
19044  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19045  }
19046  }
19047  if(TrainID != -1)
19048  {
19049  if(!TrainController->TrainVectorAtIdent(64, TrainID).Stopped())
19050  {
19051  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19052  }
19053  }
19054  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19055  {
19056  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
19057  ReturnFlag = InRouteFalse;
19058  AllRoutes->RouteTruncateFlag = false;
19059  Utilities->CallLogPop(1941);
19060  return;
19061  }
19062  if(b == int(TruncatePDElementPos))
19063  {
19064  break; // OK found truncate element & no flashing LC in front
19065  }
19066  }
19067  }
19068  else if(TruncateType == NextSignalTruncate) //added at v2.15.0
19069  {
19070  //first look forward from truncate point to the next facing signal, which must be mid-route or wouldn't reach here
19071  TPrefDirElement TempElement;
19072  LastElementToBeTruncated = -1;
19073  for(unsigned int b = TruncatePDElementPos; b < PrefDirSize(); b++)
19074  {
19075  TempElement = PrefDirVector.at(b);
19076  if(TempElement.Config[TempElement.XLinkPos] == Signal) //found it
19077  {
19078  LastElementToBeTruncated = int(b) - 1;
19079  break;
19080  }
19081  }
19082  for(int b = LastElementToBeTruncated; b >= 0; b--) //just look for train in section to be erased
19083  {
19084  int TrainID = Track->TrackElementAt(1683, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19085  if(PrefDirVector.at(b).TrackType == Bridge)
19086  {
19087  if(PrefDirVector.at(b).XLinkPos < 2)
19088  {
19089  TrainID = Track->TrackElementAt(1684, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19090  }
19091  else
19092  {
19093  TrainID = Track->TrackElementAt(1685, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19094  }
19095  }
19096  if(TrainID != -1)
19097  {
19098  if(!TrainController->TrainVectorAtIdent(72, TrainID).Stopped())
19099  {
19100  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19101  }
19102  }
19103  if(Track->IsLCBarrierFlashingAtHV(6, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19104  {
19105  TrainController->StopTTClockMessage(178, "Can't cancel a route containing a level crossing that is changing state");
19106  ReturnFlag = InRouteFalse;
19107  AllRoutes->RouteTruncateFlag = false;
19108  Utilities->CallLogPop(2713);
19109  return;
19110  }
19111  if(b == int(TruncatePDElementPos))
19112  {
19113  break; // OK found truncate element & no flashing LC in front
19114  }
19115  }
19116  //create a new route from the signal forwards to re-instate later
19117  ReinstatementRoute = *this;
19118 // ReinstatementRoute.RouteID = AllRoutes->NextRouteID; //this is allocated when store the route later on
19119 // AllRoutes->NextRouteID++;
19120  ReinstatementRoute.StartRoutePosition = PrefDirVector.at(LastElementToBeTruncated + 1).TrackVectorPosition;
19121  ReinstatementRoute.StartElement1 = PrefDirVector.at(LastElementToBeTruncated + 1);
19122  ReinstatementRoute.StartElement2 = PrefDirVector.at(LastElementToBeTruncated + 1);
19123  ReinstatementRoute.PrefDirVector.erase(ReinstatementRoute.PrefDirVector.begin(), ReinstatementRoute.PrefDirVector.begin() + LastElementToBeTruncated + 1);
19124  ReturnFlag = InRouteTrue;
19125  }
19126  else if(TruncateType == FrontTruncate)//front truncate //added at v2.15.0
19127  {
19128  for(unsigned int b = 0; b < PrefDirSize(); b++) //search forwards
19129  {
19130  int TrainID = Track->TrackElementAt(1577, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19131  if(PrefDirVector.at(b).TrackType == Bridge)
19132  {
19133  if(PrefDirVector.at(b).XLinkPos < 2)
19134  {
19135  TrainID = Track->TrackElementAt(1557, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19136  }
19137  else
19138  {
19139  TrainID = Track->TrackElementAt(1558, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19140  }
19141  }
19142  if(TrainID != -1)
19143  {
19144  if(!TrainController->TrainVectorAtIdent(65, TrainID).Stopped())
19145  {
19146  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19147  }
19148  }
19149  if(Track->IsLCBarrierFlashingAtHV(4, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19150  {
19151  TrainController->StopTTClockMessage(143, "Can't cancel a route containing a level crossing that is changing state");
19152  ReturnFlag = InRouteFalse;
19153  AllRoutes->RouteTruncateFlag = false;
19154  Utilities->CallLogPop(2571);
19155  return;
19156  }
19157  if(b == TruncatePDElementPos)
19158  {
19159  break; // OK found truncate element & no flashing LC behind
19160  }
19161  }
19162  }
19163  else //FullTruncate
19164  {
19165  for(unsigned int b = 0; b < PrefDirSize(); b++) //search the entire route forwards
19166  {
19167  int TrainID = Track->TrackElementAt(1559, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
19168  if(PrefDirVector.at(b).TrackType == Bridge)
19169  {
19170  if(PrefDirVector.at(b).XLinkPos < 2)
19171  {
19172  TrainID = Track->TrackElementAt(1560, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
19173  }
19174  else
19175  {
19176  TrainID = Track->TrackElementAt(1561, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
19177  }
19178  }
19179  if(TrainID != -1)
19180  {
19181  if(!TrainController->TrainVectorAtIdent(66, TrainID).Stopped())
19182  {
19183  MovingTrainOccupyingRoute = true; // train is on the route to be truncated & moving
19184  }
19185  }
19186  if(Track->IsLCBarrierFlashingAtHV(5, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
19187  {
19188  TrainController->StopTTClockMessage(144, "Can't cancel a route containing a level crossing that is changing state");
19189  ReturnFlag = InRouteFalse;
19190  AllRoutes->RouteTruncateFlag = false;
19191  Utilities->CallLogPop(2572);
19192  return;
19193  }
19194  }
19195  }
19196  if(PrefDirVector.at(TruncatePDElementPos).TrackType == Bridge)
19197  {
19198  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncation point");
19199  ReturnFlag = InRouteFalse;
19200  AllRoutes->RouteTruncateFlag = false;
19201  Utilities->CallLogPop(338);
19202  return;
19203  }
19204  if(((TruncatePDElementPos == 1) && (TruncateType == BackTruncate)) || ((TruncatePDElementPos == (PrefDirSize() - 2)) && (TruncateType == FrontTruncate)))
19205  {
19206  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
19207  ReturnFlag = InRouteFalse;
19208  AllRoutes->RouteTruncateFlag = false;
19209  Utilities->CallLogPop(339);
19210  return;
19211  }
19212 
19213  if((TruncatePDElementPos > 0) && (TruncateType == BackTruncate))
19214  {
19215  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1);
19216  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19217  {
19218  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19219  {
19220  TrainController->StopTTClockMessage(145, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19221  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19222  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19223  "or to remove the whole route select the first track element in the route");
19224  ReturnFlag = InRouteFalse;
19225  AllRoutes->RouteTruncateFlag = false;
19226  Utilities->CallLogPop(340);
19227  return;
19228  }
19229  }
19230  else //this isn't appropriate for front truncate
19231  {
19232  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19233  {
19234  TrainController->StopTTClockMessage(60, "Can't leave points, bridge or crossover as the last route element");
19235  ReturnFlag = InRouteFalse;
19236  AllRoutes->RouteTruncateFlag = false;
19237  Utilities->CallLogPop(341);
19238  return;
19239  }
19240  }
19241  }
19242 
19243  else if((TruncatePDElementPos < (PrefDirSize() - 1)) && (TruncateType == FrontTruncate))
19244  {
19245  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos + 1);
19246  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
19247  {
19248  if(TempElement.Config[TempElement.XLinkPos] != Signal)
19249  {
19250  TrainController->StopTTClockMessage(146, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19251  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19252  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19253  "or to remove the whole route select the first track element in the route");
19254  ReturnFlag = InRouteFalse;
19255  AllRoutes->RouteTruncateFlag = false;
19256  Utilities->CallLogPop(2573);
19257  return;
19258  }
19259  }
19260 /*
19261  else //red route //not appropriate for front truncate because the position in advance of the truncation position is to be truncated, it won't be left
19262  { // deleted at v2.21.0
19263  if(TruncatePDElementPos > 0)
19264  {
19265  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos - 1); //element behind truncation point
19266  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
19267  {
19268  TrainController->StopTTClockMessage(147, "Can't leave points, bridge or crossover as the last route element");
19269  ReturnFlag = InRouteFalse;
19270  AllRoutes->RouteTruncateFlag = false;
19271  Utilities->CallLogPop(2574);
19272  return;
19273  }
19274  }
19275  }
19276 */
19277  }
19278 
19279  else if(TruncatePDElementPos == 0) //full truncate
19280  {
19281  TPrefDirElement TempElement = PrefDirVector.at(TruncatePDElementPos);
19282  if(TempElement.AutoSignals) //PrefDir route ok as can start after a signal that is in a blue route
19283  {
19284  if((TempElement.Config[TempElement.XLinkPos] != Signal) && (TempElement.Config[TempElement.ELinkPos] != End))
19285  {
19286  TrainController->StopTTClockMessage(148, "Invalid green or blue route truncation position:\n\nto truncate from the start of the route select a position immediately before a facing signal "
19287  "that lies within the route;\n\nto truncate to the end of the route select a position immediately after a facing signal "
19288  "that lies within the route;\n\nto truncate to the next signal that isn't the end of the route select a signal to truncate from;\n\n"
19289  "or to remove the whole route select the first track element in the route");
19290  ReturnFlag = InRouteFalse;
19291  AllRoutes->RouteTruncateFlag = false;
19292  Utilities->CallLogPop(2575);
19293  return;
19294  }
19295  }
19296  else if(TempElement.PrefDirRoute) //red routes always ok for full truncate as can't leave a bridge/crossover/points as last element in route
19297  {
19298  if(TempElement.TrackType == Bridge)
19299  {
19300  TrainController->StopTTClockMessage(149, "Can't select a bridge as a route truncation point"); //should have been caught above but include for completeness
19301  ReturnFlag = InRouteFalse;
19302  AllRoutes->RouteTruncateFlag = false;
19303  Utilities->CallLogPop(2576);
19304  return;
19305  }
19306  }
19307  }
19308 
19309  int ThisRouteNumber;
19311 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
19312 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
19313 
19314 // check if part of this route already locked & disallow if so
19315  if(!(AllRoutes->LockedRouteVector.empty()))
19316  {
19318  {
19319  if(LRVIT->RouteNumber == ThisRouteNumber)
19320  {
19321  TrainController->StopTTClockMessage(61, "Can't truncate a route that contains a locked section");
19322  ReturnFlag = InRouteFalse;
19323  AllRoutes->RouteTruncateFlag = false;
19324  Utilities->CallLogPop(749);
19325  return;
19326  }
19327  }
19328  }
19329 
19330  unsigned int LookBackwardsFromHere = 0; //added at v2.15.0 - covers front & full truncate & search starts here and looks backwards to see if a train
19331  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //is within 3 running signals on this or linked rearwards routes, NextSigTruncate added at v2.21.0
19332  {
19333  LookBackwardsFromHere = TruncatePDElementPos;
19334  }
19335 
19336 // RouteLockingRequired should be ok with the above mod but need to lock either forwards or backwards
19337  int RearPosition; //these are the PDElement positions for the route section to be removed and/or locked (inclusive)
19338  int FrontPosition;
19339 
19340  if(AllRoutes->RouteLockingRequired(0, ThisRouteNumber, LookBackwardsFromHere) || MovingTrainOccupyingRoute) // added MovingTrainOccupyingRoute at v2.1.0,
19341  // before v2.1.0 RouteLockingRequired only checked for trains approaching
19342  {
19343  if(TruncateType == NextSignalTruncate) //added at v2.21.0 - don't allow trucation as would likely need to lock route further forwards than next signal
19344  {
19345  TrainController->StopTTClockMessage(179, "Unable to truncate to next signal when route locking is required. To apply locking truncate from the element "
19346  "immediately after the signal, this will lock the remainder of the route ");
19347  ReturnFlag = InRouteFalse;
19348  AllRoutes->RouteTruncateFlag = false;
19349  Utilities->CallLogPop(2714);
19350  return;
19351  }
19352  else
19353  {
19356  int button = Application->MessageBox(L"Moving train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
19357  L"Warning!", MB_YESNO | MB_ICONWARNING);
19358  TrainController->BaseTime = TDateTime::CurrentDateTime();
19360  if(button == IDNO)
19361  {
19362  ReturnFlag = InRouteTrue; // still return true even though don't act on it
19363  AllRoutes->RouteTruncateFlag = false;
19364  Utilities->CallLogPop(342);
19365  return;
19366  }
19367  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition).ElementID);
19368  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
19369  TAllRoutes::TLockedRouteClass LockedRoute;
19370  bool ExistingLockedRouteModified = false;
19371  LockedRoute.RouteNumber = ThisRouteNumber;
19372  if(TruncateType == BackTruncate)
19373  {
19374  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19375  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19376  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19377  }
19378  else if(TruncateType == FrontTruncate)
19379  {
19380  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19381  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(TruncatePDElementPos).TrackVectorPosition;
19382  LockedRoute.LastXLinkPos = PrefDirVector.at(TruncatePDElementPos).XLinkPos;
19383  }
19384  else //FullTruncate
19385  {
19386  LockedRoute.RearTrackVectorPosition = PrefDirVector.at(0).TrackVectorPosition;
19387  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
19388  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
19389  }
19390 
19391  LockedRoute.LockStartTime = TrainController->TTClockTime;
19392  // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
19393  // to use the new RearTrackVectorPosition & LockStartTime (shouldn't as should have been rejected earlier if part-locked, but leave in)
19394  if(!AllRoutes->LockedRouteVector.empty())
19395  {
19396  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
19397  LRVIT++)
19398  {
19399  if(LRVIT->RouteNumber == ThisRouteNumber)
19400  {
19401  LRVIT->RearTrackVectorPosition = LockedRoute.RearTrackVectorPosition;
19402  LRVIT->LockStartTime = LockedRoute.LockStartTime;
19403  ExistingLockedRouteModified = true;
19404  }
19405  }
19406  }
19407  if(!ExistingLockedRouteModified)
19408  {
19409  AllRoutes->LockedRouteVector.push_back(LockedRoute);
19410  }
19411  if(TruncateType == BackTruncate)
19412  {
19413  AllRoutes->SetAllRearwardsSignals(2, 0, ThisRouteNumber, TruncatePDElementPos);
19414  RearPosition = TruncatePDElementPos;
19415  FrontPosition = PrefDirSize() - 1;
19416  }
19417  else if(TruncateType == FrontTruncate)
19418  {
19419  AllRoutes->SetAllRearwardsSignals(13, 0, ThisRouteNumber, 0);
19420  RearPosition = 0;
19421  FrontPosition = TruncatePDElementPos;
19422  }
19423  else //FullTruncate
19424  {
19425  AllRoutes->SetAllRearwardsSignals(14, 0, ThisRouteNumber, 0);
19426  RearPosition = 0;
19427  FrontPosition = PrefDirSize() - 1;
19428  }
19429  // for(int c = PrefDirSize() - 1; c >= (int)TruncatePDElementPos; c--) // must use int for >= test to succeed when b == 0
19430  for(int c = FrontPosition; c >= RearPosition; c--)
19431  {
19432  // return all signals to red in route section to be truncated
19433  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, ThisRouteNumber).PrefDirVector.at(c);
19434  TTrackElement& TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
19435  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
19436  {
19437  TrackElement.Attribute = 0;
19438  Track->PlotSignal(2, TrackElement, Display);
19439  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
19440  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
19441  }
19442  }
19443  // Display->Update();//not needed as Clearand... called on return from SearchAllRoutesAndTruncate in InterfaceUnit
19444  ReturnFlag = InRouteTrue;
19445  }
19446  }
19447  else //route locking not required
19448  {
19449  if((TruncateType == BackTruncate) || (TruncateType == NextSignalTruncate)) //need to erase the whole route to the end, the new bit will be re-instated later
19450  { //for NextSignalTruncate
19451  RearPosition = TruncatePDElementPos;
19452  FrontPosition = PrefDirSize() - 1;
19453  AllRoutes->SetAllRearwardsSignals(21, 0, ThisRouteNumber, TruncatePDElementPos);
19454  }
19455  else if(TruncateType == FrontTruncate)
19456  {
19457  RearPosition = 0;
19458  FrontPosition = TruncatePDElementPos;
19459  AllRoutes->SetAllRearwardsSignals(15, 0, ThisRouteNumber, 0);
19460  }
19461  else //FullTruncate
19462  {
19463  RearPosition = 0;
19464  FrontPosition = PrefDirSize() - 1;
19465  AllRoutes->SetAllRearwardsSignals(16, 0, ThisRouteNumber, 0);
19466  }
19467 
19468  //now (before truncate route) store the front and rear PrefDir elements of the route for later adaptation (will only be used for blue routes)
19469  //into adjacent red or green routes if there are any (after the truncation/removal)
19470 
19471  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(260, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19472  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(261, 0);
19473 // bool AddRedAtEnd = false, AddRedAtStart = false, AddGreenAtEnd = false, AddGreenAtStart = false;
19474 
19475  for(int c = FrontPosition; c >= RearPosition; c--) //truncate or remove the route
19476  {
19477  AllRoutes->RemoveRouteElement(5, PrefDirVector.at(c).HLoc, PrefDirVector.at(c).VLoc, PrefDirVector.at(c).ELink);
19478  ReturnFlag = InRouteTrue;
19479  }
19480 
19481  if(TruncateType == NextSignalTruncate) //re-instate the saved route
19482  {
19483  AllRoutes->RouteTruncateFlag = false; //added at v2.22.0, not truncating any longer so don't want to set SkipForwardLook when setting rearward signals
19484  AllRoutes->StoreOneRoute(3, &ReinstatementRoute);
19486  int RouteNumber = AllRoutes->GetRouteVectorNumber(8, IDInt(RouteID));
19487  AllRoutes->SetAllRearwardsSignals(22, 0, RouteNumber, ReinstatementRoute.PrefDirSize() - 1); //sets signals for the re-instated route
19488  }
19489  if(LastPDElement.AutoSignals)
19490  {
19491  ReclaimSignalsForNonAutoSigRoutes(0, LastPDElement, FirstPDElement);
19492  }
19493  }
19494 
19495  AllRoutes->CheckMapAndRoutes(5); // test
19496  ReturnFlag = InRouteTrue;
19497  AllRoutes->RouteTruncateFlag = false;
19498  Utilities->CallLogPop(344);
19499 }
19500 
19501 // ---------------------------------------------------------------------------
19502 
19504 {
19505 /*
19506 Need to ensure that green routes always end on a signal (or continuation, but continuations aren't relevant for these purposes) as they can't be extended from other than a
19507 signal.
19508 For green/red routes, a new route that is created FROM a signal - that signal stays in the original route that ended there,
19509  but a new route that is created TO a signal - that signal becomes part of the new route.
19510 For blue routes, a new route created FROM and/or TO a signal - that signal becomes part of the blue route.
19511 So, truncating a blue route from the front leaves a green/red route ending short of the signal - add green/red signal to route at end of route
19512  truncating a blue route from the back leaves a green/red route starting behind the signal - add green/red signal to route at start of route
19513  truncating a red route from the front (in advance of a facing red route signal) ok as the signal is still in the (single element) red route and still allows trains to pass
19514  truncating a red route from the back (anywhere in the red route except as above) ok as at worst (and done deliberately) the red route stops short of a signal but can be extended to it
19515  truncating a green route from the front (in advance of a facing green route signal) ok as the signal is still in the (single element) green route and still allows trains to pass
19516  truncating a green route from the back (in rear of a green route signal) ok as signal still in green route
19517 */
19518 
19519  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ", LastPDElement TrackID " +
19520  Track->TrackElementAt(1562, LastPDElement.TrackVectorPosition).ElementID + ", FirstPDElement TrackID " +
19521  Track->TrackElementAt(1563, FirstPDElement.TrackVectorPosition).ElementID);
19522  if(!LastPDElement.AutoSignals) //shouldn't be called other than for a blue route
19523  {
19524  Utilities->CallLogPop(2578);
19525  return;
19526  }
19527  TPrefDirElement NewGreenFirstPDElement, NewRedFirstPDElement, NewGreenLastPDElement, NewRedLastPDElement;
19528  int RouteColour;
19529  //check if there's a linked forward route missing a signal and if so add it (will only apply for blue routes)
19530  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19531  {
19532  TPrefDirElement FirstForwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(0);
19533  if(FirstForwardLinkedPDElement.Conn[FirstForwardLinkedPDElement.ELinkPos] == LastPDElement.TrackVectorPosition)
19534  { //found a linked forward route
19535  //check if signal behind this route has been removed from the blue route
19536  if(!AllRoutes->TrackIsInARoute(19, LastPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19537  { //signal needs to be added at start of this linked route
19538 
19539  RouteColour = FirstForwardLinkedPDElement.GetRouteColour(FirstForwardLinkedPDElement.EXGraphicPtr);
19540  if(RouteColour == 1) //red route
19541  {
19542  NewRedFirstPDElement = LastPDElement;
19543  NewRedFirstPDElement.AutoSignals = false;
19544  NewRedFirstPDElement.PrefDirRoute = false;
19545  NewRedFirstPDElement.EXGraphicPtr = NewRedFirstPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19546  NewRedFirstPDElement.IsARoute = true;
19547  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(31, x);
19548  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewRedFirstPDElement); //insert at front
19549  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19550  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19551  {
19552  if(R2MMIt->second.first == int(x))
19553  {
19554  R2MMIt->second.second++;
19555  }
19556  }
19557  AllRoutes->Route2MultiMapInsert(1, NewRedFirstPDElement.HLoc, NewRedFirstPDElement.VLoc, NewRedFirstPDElement.ELink, x, 0); //0 is new first element number
19558  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19559  AllRoutes->SetAllRearwardsSignals(17, 0, x, AllRoutes->GetFixedRouteAt(225, x).PrefDirVector.size() - 1); //should be red but make sure
19560  }
19561  else if(RouteColour == 2) //green route
19562  {
19563  NewGreenFirstPDElement = LastPDElement;
19564  NewGreenFirstPDElement.AutoSignals = false;
19565  NewGreenFirstPDElement.PrefDirRoute = true;
19566  NewGreenFirstPDElement.EXGraphicPtr = NewGreenFirstPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19567  NewGreenFirstPDElement.IsARoute = true;
19568  TOneRoute &RouteToBeExtended = AllRoutes->GetModifiableRouteAt(32, x);
19569  RouteToBeExtended.PrefDirVector.insert(RouteToBeExtended.PrefDirVector.begin(), 1, NewGreenFirstPDElement); //insert at front
19570  TAllRoutes::TRoute2MultiMapIterator R2MMIt; //first increment all PrefDirVector numbers as new entry going at start
19571  for(R2MMIt = AllRoutes->Route2MultiMap.begin(); R2MMIt != AllRoutes->Route2MultiMap.end(); R2MMIt++)
19572  {
19573  if(R2MMIt->second.first == int(x))
19574  {
19575  R2MMIt->second.second++;
19576  }
19577  }
19578  AllRoutes->Route2MultiMapInsert(2, NewGreenFirstPDElement.HLoc, NewGreenFirstPDElement.VLoc, NewGreenFirstPDElement.ELink, x, 0); //0 is new first element number
19579  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19580  AllRoutes->SetAllRearwardsSignals(18, 0, x, AllRoutes->GetFixedRouteAt(226, x).PrefDirVector.size() - 1); //should be red but make sure
19581  }
19582  }
19583  break; //no point looking any further
19584  }
19585  }
19586 
19587 //check if there's a linked rearward route missing a signal and if so add it
19588  for(unsigned int x = 0; x < AllRoutes->AllRoutesVector.size(); x++)
19589  {
19590  TPrefDirElement LastRearwardLinkedPDElement = AllRoutes->AllRoutesVector.at(x).PrefDirVector.at(AllRoutes->AllRoutesVector.at(x).PrefDirVector.size() - 1);
19591  if(LastRearwardLinkedPDElement.Conn[LastRearwardLinkedPDElement.XLinkPos] == FirstPDElement.TrackVectorPosition)
19592  { //found a linked rearward route
19593  //check if signal in front of this route has been removed from the blue route
19594  if(!AllRoutes->TrackIsInARoute(20, FirstPDElement.TrackVectorPosition, 0)) //use 0 for LinkPos as it is a signal so only LinkPos 0 & 1 in use
19595  { //signal needs to be added at end of this linked route
19596 
19597  RouteColour = LastRearwardLinkedPDElement.GetRouteColour(LastRearwardLinkedPDElement.EXGraphicPtr);
19598  if(RouteColour == 1) //red route
19599  {
19600  NewRedLastPDElement = FirstPDElement;
19601  NewRedLastPDElement.AutoSignals = false;
19602  NewRedLastPDElement.PrefDirRoute = false;
19603  NewRedLastPDElement.EXGraphicPtr = NewRedLastPDElement.GetRouteGraphicPtr(0, 0); //not autosigs & not prefdir
19604  AllRoutes->AddRouteElement(4, NewRedLastPDElement.HLoc, NewRedLastPDElement.VLoc, NewRedLastPDElement.ELink, x, NewRedLastPDElement);
19605  //can use this as adding to the end of the route
19606  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19607  AllRoutes->SetAllRearwardsSignals(19, 0, x, AllRoutes->GetFixedRouteAt(223, x).PrefDirVector.size() - 1); //should be red but make sure
19608  }
19609  else if(RouteColour == 2) //green route
19610  {
19611  NewGreenLastPDElement = FirstPDElement;
19612  NewGreenLastPDElement.AutoSignals = false;
19613  NewGreenLastPDElement.PrefDirRoute = true;
19614  NewGreenLastPDElement.EXGraphicPtr = NewGreenLastPDElement.GetRouteGraphicPtr(0, 1); //not autosigs & prefdir
19615  AllRoutes->AddRouteElement(5, NewGreenLastPDElement.HLoc, NewGreenLastPDElement.VLoc, NewGreenLastPDElement.ELink, x, NewGreenLastPDElement);
19616  //can use this as adding to the end of the route
19617  AllRoutes->RouteTruncateFlag = false; //no longer truncating at this point
19618  AllRoutes->SetAllRearwardsSignals(20, 0, x, AllRoutes->GetFixedRouteAt(224, x).PrefDirVector.size() - 1); //should be red but make sure
19619  }
19620  }
19621  break; //no point looking any further
19622  }
19623  }
19624  Utilities->CallLogPop(2579);
19625 }
19626 
19627 // ---------------------------------------------------------------------------
19628 
19630 /*
19631  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
19632  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
19633  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
19634  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
19635  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
19636  the route colours.
19637 */
19638 {
19639  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
19640  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
19642  int RouteNumber;
19643  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
19644  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
19645  //these added at v2.15.0
19646  TPrefDirElement LastPDElement = GetFixedPrefDirElementAt(263, PrefDirSize() - 1); //these will persist after the actual PDElements have been removed
19647  TPrefDirElement FirstPDElement = GetFixedPrefDirElementAt(264, 0);
19648 
19649  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
19650  {
19651  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
19652  {
19653  if(PrefDirVector.at(x).TrackType == SignalPost)
19654  {
19655  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
19656  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
19657  }
19658  }
19659 // AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0); //dropped at v2.17.0 in favour of setting all signals after route removal (see below)
19660  //Fault found on B'ham when train (2A09) exited from Snow Hill terminal platform (no signal) when orce cancelled
19661  //route above, but when rearwards signals set the route to be cancelled still exists, so setting signals first uses
19662  //forward look when it finds a red signal in the route to be cancelled, so first signal in rear route becames yellow
19663  //when should have been be red.
19664 // already set all signals to red in route so start at start of route for further rearwards signal setting <- comment invalid after above
19665  }
19666  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
19667  {
19668  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
19669  }
19670 
19671  if(LastPDElement.AutoSignals) //added at v2.15.0
19672  {
19673  ReclaimSignalsForNonAutoSigRoutes(1, LastPDElement, FirstPDElement);
19674  }
19675 
19676  if(AllRoutes->AllRoutesVector.size() > 0) //added at v2.17.0 - see above
19677  {
19678  for(TAllRoutes::TAllRoutesVectorIterator ARVIt = AllRoutes->AllRoutesVector.begin(); ARVIt < AllRoutes->AllRoutesVector.end(); ARVIt++)
19679  {
19680  ARVIt->SetRouteSignals(14);
19681  }
19682  }
19683  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
19684  AllRoutes->CheckMapAndRoutes(9); // test
19685  TrainController->BaseTime = TDateTime::CurrentDateTime();
19687  Utilities->CallLogPop(345);
19688  return;
19689 }
19690 
19691 // ---------------------------------------------------------------------------
19692 
19693 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19694 /*
19695  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
19696 */
19697 {
19698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
19699  AnsiString((short)PrefDirRoute));
19700  if(SearchVector.empty())
19701  {
19702  Utilities->CallLogPop(1149);
19703  return;
19704  }
19705  for(unsigned int b = 0; b < SearchVector.size(); b++)
19706  {
19709  PrefDirRoute);
19710  }
19711  Utilities->CallLogPop(346);
19712 }
19713 
19714 // ---------------------------------------------------------------------------
19715 
19716 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
19717 /*
19718  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
19719  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
19720  TOneRoute.
19721 */
19722 {
19723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteFlashValues," + AnsiString((short)AutoSigsFlag) + "," +
19724  AnsiString((short)PrefDirRoute));
19725  RouteFlash.RouteFlashVector.clear();
19726  TRouteFlashElement RouteFlashElement;
19727 
19728  for(unsigned int b = 0; b < SearchVector.size(); b++)
19729  {
19730  int H = GetFixedSearchElementAt(11, b).HLoc;
19731  int V = GetFixedSearchElementAt(12, b).VLoc;
19733  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
19734  RouteFlashElement.HLoc = H;
19735  RouteFlashElement.VLoc = V;
19737  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
19738  }
19739  Utilities->CallLogPop(348);
19740 }
19741 
19742 // ---------------------------------------------------------------------------
19743 
19744 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
19745 {
19746  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
19747  if(!PrefDirVector.empty())
19748  {
19749  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
19750  {
19751  int H = PrefDirPtr->HLoc;
19752  int V = PrefDirPtr->VLoc;
19753  // check for any LCs that are closed to trains & set the flash values and store in the vector
19754  if(Track->IsLCAtHV(39, H, V))
19755  {
19756  if(Track->IsLCBarrierUpAtHV(0, H, V))
19757  {
19758  Track->LCChangeFlag = true;
19759  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
19760  CLC.HLoc = H;
19761  CLC.VLoc = V;
19763  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
19766  if(PrefDirRoute)
19767  {
19768  CLC.TypeOfRoute = 1;
19769  }
19770  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
19771  Track->ChangingLCVector.push_back(CLC);
19772  }
19773  }
19774  }
19775  }
19776  Utilities->CallLogPop(1948);
19777 }
19778 
19779 // ---------------------------------------------------------------------------
19780 
19782 /*
19783  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19784  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
19785  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19786  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19787 */
19788 {
19789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
19790  if(!OverlayPlotted)
19791  {
19792  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19793  {
19794  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19795  {
19796  continue;
19797  }
19798  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
19799  Display->Update();
19800  }
19801  OverlayPlotted = true;
19802  }
19803  Utilities->CallLogPop(349);
19804 }
19805 
19806 // ---------------------------------------------------------------------------
19807 
19809 /*
19810  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
19811  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
19812  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
19813  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
19814 */
19815 {
19816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
19817  if(OverlayPlotted)
19818  {
19819  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
19820  {
19821  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
19822  {
19823  continue;
19824  }
19825  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
19826  Display->Update();
19827  }
19828  OverlayPlotted = false;
19829  }
19830  Utilities->CallLogPop(350);
19831 }
19832 
19833 // ---------------------------------------------------------------------------
19834 
19835 bool TOneRoute::SignalHasFailed(int Caller) //added at v2.13.0
19836 {
19837 /*enter with SearchVector fully populated & with a legitimate route found, return true for failure.
19838 Look along SearchVector backwards, skip first signal found (i.e. last in route), but for all others
19839 including first signal in route offer chance to fail (since they all change aspect), but if find any failed point
19840 where no route available (i.e. a dead end, points checked after search in PointsToBeChanged) then return false - i.e. don't
19841 allow signal failure in an unviable route. If fail (i.e. prior to returning true), alter graphic, send
19842 messages, and allocate a repair time similar to points)
19843 */
19844 
19845  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SignalHasFailed");
19846  if((Utilities->FailureMode == FNil) || (SearchVector.size() < 2)) //added (SearchVector.size() < 2) at v2.14.0 as rely on it being at least 2 below
19847  {
19848  Utilities->CallLogPop(2528);
19849  return(false);
19850  }
19851  bool FirstSignalFound = false;
19852  for(TPrefDirVector::iterator PDVIt = SearchVector.end() - 1; PDVIt >= SearchVector.begin(); PDVIt--)
19853  {
19854  TTrackElement &TE = Track->TrackElementAt(1530, PDVIt->TrackVectorPosition);
19855 //check for a failed point where needs to change to make the route
19856 //shouldn't be any but check to be safe
19857  int Attr = TE.Attribute;
19858  if(PDVIt->TrackType == Points)
19859  {
19860  if((PDVIt->ELinkPos == 1) || (PDVIt->XLinkPos == 1)) // 1=want to go straight
19861  {
19862  if(Attr == 1) //currently set to diverge
19863  {
19864  if(TE.Failed)
19865  {
19866  Utilities->CallLogPop(2529);
19867  return(false); //return without further checking
19868  }
19869  }
19870  }
19871  else if((PDVIt->ELinkPos == 3) || (PDVIt->XLinkPos == 3)) // 3=want to diverge
19872  {
19873  if(Attr == 0) //currently set to go straight
19874  {
19875  if(TE.Failed)
19876  {
19877  Utilities->CallLogPop(2530);
19878  return(false); //return without further checking
19879  }
19880  }
19881  }
19882  }
19883  //now need to check if PDVIt->XLinkPos is set (> -1) as if an unrestricted route and start on a signal not in an existing route then XLinkPos won't be set
19884  //changed at v2.14.0 to ensure both prefdir & unrestricted routes can have first signal fail (by determining what XLinkPos should be and using it, but not changing
19885  //the search vector)
19886  int XLinkPosition = PDVIt->XLinkPos;
19887  if(PDVIt->XLinkPos == -1)
19888  {
19889  if(PDVIt < (SearchVector.end() - 1)) //no good if end element as need to examine the later one, though shouldn't have XLinkPos unset if so
19890  {
19891  for(int x = 0; x < 4; x++)
19892  {
19893  if(PDVIt->Conn[x] == (PDVIt + 1)->TrackVectorPosition)
19894  {
19895  XLinkPosition = x;
19896  break;
19897  }
19898  }
19899  }
19900  else
19901  {
19902  Utilities->CallLogPop(2549);
19903  return(false); //no point going any further
19904  }
19905  }
19906  if(XLinkPosition > -1) //should be by now but be safe
19907  {
19908  if(!FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19909  {
19910  FirstSignalFound = true; //the first signal doesn't change aspect
19911  continue;
19912  }
19913  else if(FirstSignalFound && (PDVIt->Config[XLinkPosition] == Signal))
19914  {
19915 /*
19916  if(TE.SigAspect == TTrackElement::GroundSignal) //dropped at v2.14.0 to allow ground signals to fail
19917  {
19918  continue; //ground signals don't fail
19919  }
19920 */
19921  if((random(Utilities->SignalChangeEventsPerFailure) == 0) && !TE.Failed) //can't fail twice
19922  {
19924  IFE.TVPos = PDVIt->TrackVectorPosition;
19925  TE.Failed = true;
19926  TE.Attribute = 0; //stop aspect
19927  Display->WarningLog(22, Utilities->Format96HHMMSS(TrainController->TTClockTime) + ": Signal failed at " + TE.ElementID);
19928  PerfLogForm->PerformanceLog(45, Utilities->Format96HHMMSS(TrainController->TTClockTime) + " WARNING: Signal failed at " + TE.ElementID);
19929  TrainController->StopTTClockMessage(132, "Signal at " + TE.ElementID +
19930  " failed when changing aspect.\nTrains can only pass under signaller control.");
19931  AllRoutes->RebuildRailwayFlag = true; //force ClearandRebuildRailway at next clock tick
19932  //set repair time, random value in minutes between 10 and 179
19933  double FailureMinutes = double(random(Utilities->MaxRandomRepairTime) + Utilities->FixedMinRepairTime); //between 10 and 179 minutes at random
19934  TDateTime RepairTime = TrainController->TTClockTime + TDateTime(FailureMinutes / 1440);
19935  IFE.RepairTime = RepairTime;
19937  Track->FailedSignalsVector.push_back(IFE);
19939  int RouteNumber; //not used
19940  if(AllRoutes->GetRouteTypeAndNumber(41, IFE.TVPos, 0, RouteNumber) != TAllRoutes::NoRoute) //otherwise Attribute already 0 so will plot red
19941  { // 0 for LinkPos ok as a signal so only one track
19942  AllRoutes->AllRoutesVector.at(RouteNumber).SetRouteSignals(12);
19943  }
19944  Utilities->CallLogPop(2535);
19945  return(true); //return so only allow one failure per route
19946  }
19947  }
19948  }
19949  }
19950  Utilities->CallLogPop(2531);
19951  return(false);
19952 }
19953 
19954 // ---------------------------------------------------------------------------
19955 // ---------------------------------------------------------------------------
19956 
19957 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
19958 {
19959  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
19960  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19961  {
19962  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
19963  }
19964  Utilities->CallLogPop(120);
19965  return(AllRoutesVector.at(At));
19966 }
19967 
19968 // ---------------------------------------------------------------------------
19969 
19971 {
19972  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
19973  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
19974  {
19975  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
19976  }
19977  Utilities->CallLogPop(121);
19978  return(AllRoutesVector.at(At));
19979 }
19980 
19981 // ---------------------------------------------------------------------------
19982 
19983 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
19984 /*
19985  Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
19986 */
19987 {
19988  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
19989  for(unsigned int a = 0; a < AllRoutesSize(); a++)
19990  {
19991  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
19992  }
19993  Utilities->CallLogPop(351);
19994 }
19995 
19996 // ---------------------------------------------------------------------------
19997 
19998 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
19999 {
20000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
20001  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20002  {
20003  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
20004  }
20005  Utilities->CallLogPop(1706);
20006 }
20007 
20008 // ---------------------------------------------------------------------------
20009 
20010 bool TAllRoutes::SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
20011 /*
20012  Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in
20013  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
20014  Messages are given in TruncateRoute. If successful the route is truncated at and including
20015  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
20016  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
20017  length (train length).
20018 */
20019 {
20020  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchAllRoutesAndTruncate," + AnsiString(HLoc) + "," +
20021  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
20022  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20023  {
20024  TTruncateReturnType ReturnFlag;
20025 // used in SetRearwardsSignalsReturnFalseForTrainInRear (called by TruncateRoute) to skip continuation & buffer attribute change
20026  GetModifiableRouteAt(7, a).TruncateRoute(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
20027  if(ReturnFlag == NotInRoute)
20028  {
20029  continue;
20030  }
20031  else if(ReturnFlag == InRouteTrue)
20032  {
20033  Utilities->CallLogPop(352);
20034  return(true);
20035  }
20036  else if(ReturnFlag == InRouteFalse)
20037  {
20038  Utilities->CallLogPop(353);
20039  return(false);
20040  }
20041  }
20042  Utilities->CallLogPop(354);
20043  return(false);
20044 }
20045 
20046 // ---------------------------------------------------------------------------
20047 
20048 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
20049 /*
20050  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
20051  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
20052 */
20053 {
20054  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
20055  AnsiString(LinkPos));
20056  if(TrackVectorPosition == -1) // allows for continuation entries & exits
20057  {
20058  Utilities->CallLogPop(355);
20059  return(false);
20060  }
20061  THVPair Route2MultiMapKeyPair;
20062 
20063  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
20064  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
20065  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20066  TRoute2MultiMapIterator Route2MultiMapIterator;
20067 
20068  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
20069  {
20070  Utilities->CallLogPop(356);
20071  return(false);
20072  }
20073  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
20074  {
20075  Utilities->CallLogPop(1422);
20076  return(true);
20077  }
20078  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1) //remainder for a bridge element
20079  {
20080  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20081 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20082 // realised after writing this that can't be points as would have been covered above, but leave anyway
20083  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
20084  Route2MultiMapIterator->second.second);
20085  EntryLinkPos = PrefDirElement1.ELinkPos;
20086  ExitLinkPos = PrefDirElement1.XLinkPos;
20087  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20088  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20089  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
20090  {
20091  Utilities->CallLogPop(357);
20092  return(true);
20093  }
20094  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
20095  {
20096  Utilities->CallLogPop(358);
20097  return(true);
20098  }
20099  }
20100  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
20101  {
20102  Utilities->CallLogPop(1423);
20103  return(true);
20104  }
20105  Utilities->CallLogPop(363);
20106  return(false); // none found
20107 }
20108 
20109 // ---------------------------------------------------------------------------
20110 
20111 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
20112  Graphics::TBitmap* &EntryDirectionGraphicPtr)
20113 /*
20114  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
20115  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
20116  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
20117  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
20118  for replotting of AutoSigsRoutes.
20119 */
20120 {
20121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
20122  AnsiString(LinkPos));
20123  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
20124  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
20125  if(TrackVectorPosition == -1)
20126  {
20127  Utilities->CallLogPop(364);
20128  return(NoRoute); // allows for continuation entries & exits
20129  }
20130  THVPair Route2MultiMapKeyPair;
20131 
20132  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
20133  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
20134  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20135  TRoute2MultiMapIterator Route2MultiMapIterator;
20136 
20137  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20138  {
20139  Utilities->CallLogPop(365);
20140  return(NoRoute); // none found
20141  }
20142  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20143  {
20144  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20145 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20146  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
20147  Route2MultiMapIterator->second.second);
20148  EntryLinkPos = PrefDirElement1.ELinkPos;
20149  ExitLinkPos = PrefDirElement1.XLinkPos;
20150  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20151  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20152  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
20153  {
20154  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20155  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
20156  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20157  {
20158  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20159  }
20160  if(PrefDirElement1.AutoSignals)
20161  {
20162  Utilities->CallLogPop(366);
20163  return(AutoSigsRoute);
20164  }
20165  else
20166  {
20167  Utilities->CallLogPop(367);
20168  return(NotAutoSigsRoute);
20169  }
20170  }
20171  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
20172  {
20173  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
20174  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
20175  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
20176  {
20177  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
20178  }
20179  if(PrefDirElement1.AutoSignals)
20180  {
20181  Utilities->CallLogPop(368);
20182  return(AutoSigsRoute);
20183  }
20184  else
20185  {
20186  Utilities->CallLogPop(369);
20187  return(NotAutoSigsRoute);
20188  }
20189  }
20190  }
20191  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20192  {
20193  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20194  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20195 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20196  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
20197  EntryLinkPos = PrefDirElement2.ELinkPos;
20198  ExitLinkPos = PrefDirElement2.XLinkPos;
20199  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20200  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20201  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
20202  {
20203  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20204  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
20205  {
20206  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20207  }
20208  if(PrefDirElement2.AutoSignals)
20209  {
20210  Utilities->CallLogPop(370);
20211  return(AutoSigsRoute);
20212  }
20213  else
20214  {
20215  Utilities->CallLogPop(371);
20216  return(NotAutoSigsRoute);
20217  }
20218  }
20219  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
20220  {
20221  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
20222  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
20223  {
20224  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
20225  }
20226  if(PrefDirElement2.AutoSignals)
20227  {
20228  Utilities->CallLogPop(372);
20229  return(AutoSigsRoute);
20230  }
20231  else
20232  {
20233  Utilities->CallLogPop(373);
20234  return(NotAutoSigsRoute);
20235  }
20236  }
20237  ItPair.second--; // the second iterator points one past the last matching value
20238  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
20239  EntryLinkPos = PrefDirElement3.ELinkPos;
20240  ExitLinkPos = PrefDirElement3.XLinkPos;
20241  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20242  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20243  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
20244  {
20245  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20246  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
20247  {
20248  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20249  }
20250  if(PrefDirElement3.AutoSignals)
20251  {
20252  Utilities->CallLogPop(374);
20253  return(AutoSigsRoute);
20254  }
20255  else
20256  {
20257  Utilities->CallLogPop(375);
20258  return(NotAutoSigsRoute);
20259  }
20260  }
20261  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
20262  {
20263  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
20264  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
20265  {
20266  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
20267  }
20268  if(PrefDirElement3.AutoSignals)
20269  {
20270  Utilities->CallLogPop(376);
20271  return(AutoSigsRoute);
20272  }
20273  else
20274  {
20275  Utilities->CallLogPop(377);
20276  return(NotAutoSigsRoute);
20277  }
20278  }
20279  }
20280  Utilities->CallLogPop(378);
20281  return(NoRoute); // none found
20282 }
20283 
20284 // ---------------------------------------------------------------------------
20285 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
20286 /*
20287  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
20288  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
20289 */
20290 {
20291  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
20292  AnsiString(LinkPos));
20293  if(TrackVectorPosition == -1)
20294  {
20295  RouteNumber = -1;
20296  Utilities->CallLogPop(379);
20297  return(NoRoute); // allows for continuation & buffer entries & exits
20298  }
20299  THVPair Route2MultiMapKeyPair;
20300 
20301  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
20302  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
20303  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
20304  TRoute2MultiMapIterator Route2MultiMapIterator;
20305 
20306  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20307  {
20308  RouteNumber = -1;
20309  Utilities->CallLogPop(380);
20310  return(NoRoute); // none found
20311  }
20312  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20313  {
20314  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20315 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20316  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
20317  Route2MultiMapIterator->second.second);
20318  EntryLinkPos = PrefDirElement1.ELinkPos;
20319  ExitLinkPos = PrefDirElement1.XLinkPos;
20320  EntryLink = PrefDirElement1.Link[EntryLinkPos];
20321  ExitLink = PrefDirElement1.Link[ExitLinkPos];
20322  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
20323  {
20324  RouteNumber = Route2MultiMapIterator->second.first;
20325  if(PrefDirElement1.AutoSignals)
20326  {
20327  Utilities->CallLogPop(381);
20328  return(AutoSigsRoute);
20329  }
20330  else
20331  {
20332  Utilities->CallLogPop(382);
20333  return(NotAutoSigsRoute);
20334  }
20335  }
20336  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
20337  {
20338  RouteNumber = Route2MultiMapIterator->second.first;
20339  if(PrefDirElement1.AutoSignals)
20340  {
20341  Utilities->CallLogPop(383);
20342  return(AutoSigsRoute);
20343  }
20344  else
20345  {
20346  Utilities->CallLogPop(384);
20347  return(NotAutoSigsRoute);
20348  }
20349  }
20350  }
20351  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20352  {
20353  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20354  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20355 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
20356  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
20357  EntryLinkPos = PrefDirElement2.ELinkPos;
20358  ExitLinkPos = PrefDirElement2.XLinkPos;
20359  EntryLink = PrefDirElement2.Link[EntryLinkPos];
20360  ExitLink = PrefDirElement2.Link[ExitLinkPos];
20361  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
20362  {
20363  RouteNumber = ItPair.first->second.first;
20364  if(PrefDirElement2.AutoSignals)
20365  {
20366  Utilities->CallLogPop(385);
20367  return(AutoSigsRoute);
20368  }
20369  else
20370  {
20371  Utilities->CallLogPop(386);
20372  return(NotAutoSigsRoute);
20373  }
20374  }
20375  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
20376  {
20377  RouteNumber = ItPair.first->second.first;
20378  if(PrefDirElement2.AutoSignals)
20379  {
20380  Utilities->CallLogPop(387);
20381  return(AutoSigsRoute);
20382  }
20383  else
20384  {
20385  Utilities->CallLogPop(388);
20386  return(NotAutoSigsRoute);
20387  }
20388  }
20389  ItPair.second--; // the second iterator points one past the last matching value
20390  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
20391  EntryLinkPos = PrefDirElement3.ELinkPos;
20392  ExitLinkPos = PrefDirElement3.XLinkPos;
20393  EntryLink = PrefDirElement3.Link[EntryLinkPos];
20394  ExitLink = PrefDirElement3.Link[ExitLinkPos];
20395  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
20396  {
20397  RouteNumber = ItPair.second->second.first;
20398  if(PrefDirElement3.AutoSignals)
20399  {
20400  Utilities->CallLogPop(389);
20401  return(AutoSigsRoute);
20402  }
20403  else
20404  {
20405  Utilities->CallLogPop(390);
20406  return(NotAutoSigsRoute);
20407  }
20408  }
20409  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
20410  {
20411  RouteNumber = ItPair.second->second.first;
20412  if(PrefDirElement3.AutoSignals)
20413  {
20414  Utilities->CallLogPop(391);
20415  return(AutoSigsRoute);
20416  }
20417  else
20418  {
20419  Utilities->CallLogPop(392);
20420  return(NotAutoSigsRoute);
20421  }
20422  }
20423  }
20424  RouteNumber = -1;
20425  Utilities->CallLogPop(393);
20426  return(NoRoute); // none found
20427 }
20428 
20429 // ---------------------------------------------------------------------------
20430 
20431 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
20432 /*
20433  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
20434  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
20435  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
20436  and Route2MultiMap.
20437 */
20438 {
20439  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
20440  TOneRoute EmptyRoute;
20441 
20442  EmptyRoute.RouteID = NextRouteID;
20443  NextRouteID++;
20444 
20445  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20446  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20447  {
20448  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
20449  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
20450  }
20451  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
20452  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
20453  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
20454  Utilities->CallLogPop(394);
20455 }
20456 
20457 // ---------------------------------------------------------------------------
20458 
20460 /*
20461  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
20462  that is already in Route is used.
20463 */
20464 {
20465  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
20466  TOneRoute EmptyRoute;
20467 
20468  EmptyRoute.RouteID = Route->RouteID;
20469 
20470  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
20471  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
20472  {
20473  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
20474  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
20475  }
20476  Utilities->CallLogPop(1579);
20477 }
20478 
20479 // ---------------------------------------------------------------------------
20480 
20481 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
20482 /*
20483  When attaching a new route section to an existing route, it is sometimes necessary to erase the
20484  original route and create a new composite route. This function Erases all elements in the route
20485  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
20486  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
20487  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
20488  that are greater than the route number that is removed. The LockedRouteVector as also searched
20489  and if any relate to the route that has been cleared they are erased too, but the fact that one
20490  has been found is recorded so that it can be re-established later.
20491 */
20492 {
20493  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
20494  THVPair Route2MultiMapKeyPair;
20495  TRoute2MultiMapEntry Route2MultiMapEntry;
20496  TRoute2MultiMapIterator Route2MultiMapIterator;
20497 
20498 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
20499 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
20500 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
20501 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
20502 // If so the locked route is removed from the locked vector and is lost.
20503  LockedRouteRearTrackVectorPosition = 0;
20504  LockedRouteLastTrackVectorPosition = 0;
20505  LockedRouteLastXLinkPos = 0;
20506  LockedRouteLockStartTime = TDateTime(0);
20507  if(!LockedRouteVector.empty())
20508  {
20509  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20510  {
20511  if(LRVIT->RouteNumber == RouteNumber)
20512  {
20513  LockedRouteRearTrackVectorPosition = LRVIT->RearTrackVectorPosition;
20514  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
20515  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
20516  LockedRouteLockStartTime = LRVIT->LockStartTime;
20517  LockedRouteFoundDuringRouteBuilding = true;
20518  LockedRouteVector.erase(LRVIT);
20519  }
20520  }
20521  }
20522  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
20523  {
20524  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
20525  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
20526  }
20527  Utilities->CallLogPop(395);
20528 }
20529 
20530 // ---------------------------------------------------------------------------
20531 
20533  TRoute2MultiMapIterator &Route2MultiMapIterator)
20534 /*
20535  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
20536  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
20537  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
20538  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
20539  are given for failure.
20540 */
20541 {
20542  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20543  AnsiString(VLoc) + "," + AnsiString(ELink));
20544  TRouteElementPair ReturnPair;
20545 
20546  ReturnPair.first = -1;
20547  ReturnPair.second = 0;
20548  THVPair Route2MultiMapKeyPair;
20549 
20550  Route2MultiMapKeyPair.first = HLoc;
20551  Route2MultiMapKeyPair.second = VLoc;
20552  TRoute2MultiMapEntry Route2MultiMapEntry;
20553 
20554  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20555  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20556 
20557  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20558  Route2MultiMapIterator = ItPair.first;
20559 
20560  if(ItPair.first == ItPair.second)
20561  {
20562  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
20563  }
20564  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
20565  {
20566  ReturnPair.first = ItPair.first->second.first;
20567  ReturnPair.second = ItPair.first->second.second;
20568  Route2MultiMapIterator = ItPair.first;
20569  Utilities->CallLogPop(396);
20570  return(ReturnPair);
20571  }
20572  ItPair.first++;
20573  if(ItPair.first == ItPair.second)
20574  {
20575  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
20576  }
20577  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
20578  {
20579  ReturnPair.first = ItPair.first->second.first;
20580  ReturnPair.second = ItPair.first->second.second;
20581  Route2MultiMapIterator = ItPair.first;
20582  Utilities->CallLogPop(397);
20583  return(ReturnPair);
20584  }
20585  Utilities->CallLogPop(398);
20586  return(ReturnPair);
20587 }
20588 
20589 // ---------------------------------------------------------------------------
20590 
20591 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
20592 /*
20593  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
20594  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
20595  RouteNumber (route position in AllRoutes vector is returned as a reference.
20596  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
20597  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
20598 */
20599 {
20600  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
20601  AnsiString(VLoc) + "," + AnsiString(ELink));
20602  THVPair Route2MultiMapKeyPair;
20603 
20604  Route2MultiMapKeyPair.first = HLoc;
20605  Route2MultiMapKeyPair.second = VLoc;
20606  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
20607 
20608  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20609 
20610  if(ItPair.first == ItPair.second)
20611  {
20612  RouteNumber = -1;
20613  Utilities->CallLogPop(2032);
20614  return(false);
20615  }
20616  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
20617  {
20618  RouteNumber = ItPair.first->second.first;
20619  Utilities->CallLogPop(2033);
20620  return(true);
20621  }
20622  ItPair.first++;
20623 
20624  if(ItPair.first == ItPair.second)
20625  {
20626  RouteNumber = -1;
20627  Utilities->CallLogPop(2034);
20628  return(false);
20629  }
20630  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
20631  {
20632  RouteNumber = ItPair.first->second.first;
20633  Utilities->CallLogPop(2035);
20634  return(true);
20635  }
20636  RouteNumber = -1;
20637  Utilities->CallLogPop(2036);
20638  return(false);
20639 }
20640 
20641 // ---------------------------------------------------------------------------
20642 
20643 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
20644 /*
20645  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
20646  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
20647  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
20648  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
20649  Called by TAllRoutes::AddRouteElement.
20650 */
20651 {
20652  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
20653  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
20654  THVPair Route2MultiMapKeyPair;
20655 
20656  Route2MultiMapKeyPair.first = HLoc;
20657  Route2MultiMapKeyPair.second = VLoc;
20658  TRoute2MultiMapEntry Route2MultiMapEntry;
20659 
20660  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
20661  TRouteElementPair RouteElementPair;
20662 
20663  RouteElementPair.first = RouteNumber;
20664  RouteElementPair.second = RouteElementNumber;
20665  Route2MultiMapEntry.second = RouteElementPair;
20666 
20667  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
20668  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
20669  {
20670  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
20671  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
20672  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
20673  {
20674  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
20675  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
20676  {
20677  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20678  }
20679  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
20680  }
20681  else
20682  // same ELink so have an error
20683  {
20684  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
20685  }
20686  }
20687  else
20688  {
20689  Route2MultiMap.insert(Route2MultiMapEntry);
20690  }
20691 // element at H&V not found in map so insert it
20692  Utilities->CallLogPop(399);
20693 }
20694 
20695 // ---------------------------------------------------------------------------
20696 
20698 /*
20699  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
20700  and the second in the reference SecondPair. If there's only one then it's the function return
20701 */
20702 {
20703  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
20704  AnsiString(VLoc));
20706 
20707  TempPair.first = -1;
20708  TempPair.second = 0;
20709  SecondPair = TempPair;
20710  TRoute2MultiMapIterator Route2MultiMapIterator;
20711  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
20712  THVPair Route2MultiMapKeyPair;
20713 
20714  Route2MultiMapKeyPair.first = HLoc;
20715  Route2MultiMapKeyPair.second = VLoc;
20716  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
20717  {
20718  Utilities->CallLogPop(400);
20719  return(TempPair);
20720  }
20721  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
20722  {
20723  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
20724  Utilities->CallLogPop(401);
20725  return(Route2MultiMapIterator->second);
20726  }
20727  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
20728  {
20729  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
20730  TempPair = ItRange.first->second;
20731  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
20732  Utilities->CallLogPop(402);
20733  return(TempPair);
20734  }
20735  Utilities->CallLogPop(403);
20736  return(TempPair);
20737 }
20738 
20739 // ---------------------------------------------------------------------------
20740 
20741 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
20742 /*
20743  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
20744  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
20745 */
20746 {
20747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
20748  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
20749  {
20750  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
20751  {
20752  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
20753  TAllRoutes::TRouteElementPair SecondPair;
20754  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
20755  if(RouteElementPair.first == -1)
20756  // failed to find element in multimap
20757  {
20758  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
20759  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
20760  }
20761  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
20762  // neither pair has expected route number
20763  {
20764  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20765  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
20766  (AnsiString)Caller);
20767  }
20768  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
20769  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
20770  {
20771  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
20772  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
20773  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
20774  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
20775  }
20776  }
20777  }
20778  unsigned int SizeVal = 0;
20779 
20780 // check map and sum of route sizes match
20781  for(unsigned int a = 0; a < AllRoutesSize(); a++)
20782  {
20783  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
20784  }
20785  if(SizeVal != Route2MultiMap.size())
20786  {
20787  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
20788  (AnsiString)Caller);
20789  }
20790  Utilities->CallLogPop(404);
20791  return;
20792 }
20793 
20794 // ---------------------------------------------------------------------------
20795 
20796 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
20797 /*
20798  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
20799  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
20800  exceed that for the erased route. Where this is so the RouteNumber is decremented.
20801 */
20802 {
20803  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
20804  if(!Route2MultiMap.empty())
20805  {
20806  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20807  {
20808  if(Route2MultiMapIterator->second.first > RouteNumber)
20809  {
20810  Route2MultiMapIterator->second.first--;
20811  }
20812  }
20813  }
20814  Utilities->CallLogPop(405);
20815 }
20816 
20817 // ---------------------------------------------------------------------------
20818 
20819 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
20820 /*
20821  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
20822  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
20823  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
20824 */
20825 {
20826  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
20827  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
20828  if(!Route2MultiMap.empty())
20829  {
20830  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
20831  {
20832  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
20833  {
20834  Route2MultiMapIterator->second.second--;
20835  }
20836  }
20837  }
20838  Utilities->CallLogPop(406);
20839 }
20840 
20841 // ---------------------------------------------------------------------------
20842 
20843 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
20844 /*
20845  Erases the route element from Route2MultiMap and from the PrefDirVector.
20846  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
20847  decremented if they are greater than the element number removed, and if the entire route is removed
20848  then the route numbers are also decremented in the map for route numbers that are greater than the route
20849  number that is removed.
20850 */
20851 {
20852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20853  AnsiString(ELink));
20854  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
20855  TRoute2MultiMapIterator Route2MultiMapIterator;
20856 
20857  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
20858  if(RequiredRoutePair.first == -1)
20859  {
20860  throw Exception("Failed to find route element in RemoveRouteElement");
20861  }
20862  Route2MultiMap.erase(Route2MultiMapIterator);
20863  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
20864 
20865 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
20866  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
20867 
20868  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
20869  {
20870  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
20871  }
20872 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
20873 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
20874 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
20875 // to check if a route element is present, and the element has already been removed from the map - see above.
20876 
20877 // before erase the element check if it's in a locked route, and if so change the RearTrackVectorPosition to the next valid (XLinkPos] element position
20878 /*
20879  int LockedVectorNumber = -1;
20880  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
20881  {
20882  LockedRouteVector.at(LockedVectorNumber).RearTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
20883  }
20884 */
20885 
20886 // erase element from route
20887  GetModifiableRouteAt(8, RequiredRoutePair.first).PrefDirVector.erase(GetModifiableRouteAt(33, RequiredRoutePair.first).PrefDirVector.begin() + RequiredRoutePair.second);
20888 // CheckMapAndRoutes();//test - drop - tested below
20889 
20890 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
20891 // be so as continuation exit is at the end of the route, and truncation is from the end
20893  {
20895  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20896  AutoSigVectorIT--)
20897  {
20898  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
20899  {
20900  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
20901  }
20902  }
20903  }
20904 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
20905 // and adjust all the corresponding route numbers
20906  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
20907  {
20908  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
20909  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
20910  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
20911 
20912 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
20913  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
20914  it is erased then - see TInterface::ApproachLocking
20915 
20916  if(LockedVectorNumber > -1)
20917  {
20918  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
20919  }
20920 */
20921  // decrement route numbers in the locked route vector whether or not this route is a locked route
20922  if(!LockedRouteVector.empty())
20923  {
20924  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
20925  {
20926  if(LRVIT->RouteNumber > RequiredRoutePair.first)
20927  {
20928  LRVIT->RouteNumber--;
20929  }
20930  }
20931  }
20933  {
20935  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
20936  AutoSigVectorIT--)
20937  {
20938  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
20939  {
20940  AutoSigVectorIT->RouteNumber--;
20941  }
20942  }
20943  }
20944  }
20945  CheckMapAndRoutes(7); // test
20946  Utilities->CallLogPop(407);
20947 }
20948 
20949 // ---------------------------------------------------------------------------
20950 
20951 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
20952 /*
20953  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
20954  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
20955  since that catches all route elements wherever created
20956 */
20957 {
20958  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
20959  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
20960  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
20961  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1); //-1 because vector has been increased by 1 above, so
20962  Utilities->CallLogPop(408); //PrefDirSize() has been increased by 1, so the new element
20963 } //number is one less than this
20964 
20965 // ---------------------------------------------------------------------------
20966 
20967 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
20968 /*
20969  Enter with signal at TrackVectorElement already set to red by the passing train.
20970  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
20971  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
20972  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
20973  case the function sets no further signals - if rear route is non-autosigs then no route behind train, if autosigs the train will have
20974  set signals in rear as it passed them.
20975 */
20976 {
20977  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
20978  "," + AnsiString(XLinkPos));
20979  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
20980  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
20981 
20982  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
20983  if(RouteElementPair.first == -1)
20984  {
20985  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
20986  }
20987  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
20988 
20989  RequiredPair = RouteElementPair;
20990  if(RouteElement.XLinkPos != XLinkPos)
20991  {
20992  if(SecondPair.first != -1)
20993  {
20994  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
20995  RequiredPair = SecondPair;
20996  if(RouteElement.XLinkPos != XLinkPos)
20997  {
20998  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
20999  }
21000  }
21001  else
21002  {
21003  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
21004  }
21005  }
21006 // new function
21007  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
21008  Utilities->CallLogPop(409);
21009 }
21010 
21011 // ---------------------------------------------------------------------------
21012 
21013 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber) //minor changes at v2.17.0
21014 /*
21015  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
21016  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
21017  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
21018  accordingly, then double yellow, then green (for 4 aspect signals). There are only 3 calls in all for any given route, and the AccessNumber
21019  changes from 0 to 1 to 2 for successive calls.
21020  Initially Attribute is set to AccessNumber to correspond to the first signal attribute to be set, then a number of validity checks
21021  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
21022  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
21023  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals - if rear
21024  route is non-autosigs then no route behind train, if autosigs the train will have set signals in rear as it passes them.
21025 */
21026 {
21027  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
21028  AnsiString(AccessNumber));
21029  TPrefDirElement RouteElement;
21030  int Attribute = AccessNumber; //was +1, but at v2.17.0 access no. increment carried out before set signals so SetRouteSignals works ok whenever called
21031 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
21032  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
21033 
21034  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
21035  {
21036  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
21037  }
21038  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
21039  {
21040  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
21041  }
21042  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
21043  x).XLinkPos] != End)
21044  {
21045  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
21046  }
21047 // new function
21048  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
21049  Utilities->CallLogPop(410);
21050 }
21051 
21052 // ---------------------------------------------------------------------------
21053 
21054 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition) //some changes at v2.17.0
21055 /*
21056  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
21057  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
21058  or (b) in a linked rear route, in which case the function sets no further signals - if rear route is non-autosigs then no route behind train,
21059  if autosigs the train will have set signals in rear as it passed them.
21060 
21061  First call SetRearwardsSignalsReturnFalseForTrainInRear (which is only called by this function) to set signals in route RouteNumber according
21062  to the received or modified (because of the forward look for buffers or continuation etc.) Attribute. If no train is found during this call
21063  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrainInRear for each rearwards linked route (without a forward look)
21064  until either reach the beginning of the last linked route or find a train in a linked rear route. If a train is found in a linked rear route
21065  then the function terminates.
21066 
21067  However if a train is found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrainInRear then need to continue after the
21068  train for an autosigs route or in case had just added a route segment behind a train that now forms part of a single continuous route for a
21069  non-autosigs route, otherwise the signals won't be set behind the train.
21070 
21071  First the route is examined element by element from the RouteStartPosition towards the start of the
21072  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
21073  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
21074  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
21075  found behind the train.
21076 
21077  Description of SetRearwardsSignalsReturnFalseForTrainInRear for reference
21078  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
21079  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
21080  rearward search, first search forwards (unless SkipForwardLook true) from the PrefDirVectorStartPosition + 1 (may be in a forward route -
21081  see FindForwardTargetSignalAttribute) in case the end of the route is a buffer, continuation, or something else that requires Attribute
21082  to be modified and modify the Attribute accordingly UNLESS (a) train or closed LC present between PrefDirVectorStartPosition & end;
21083  (b) route in ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals),
21084  or (c) truncating a route.
21085 
21086  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
21087  signal or something else that requires Attribute to change. If find a signal set its Attribute to the current Attribute value up to a maximum
21088  of 3, and replot the signal as well as the required route and direction (if required) graphics, then increment Attribute up to a max. of 3
21089  [addition at v2.9.2: if signal or element beyond it is in a locked route then set signal to red & change Attribute to 0 - this fault reported
21090  by Simon Banham 21/07/21 as an image]. and continue working backwards for the next signal (or train - return false as before) and so on.
21091  On completion Attribute is passed back from the function as a reference. If no train is found before the beginning of the route is reached
21092  the function returns true.
21093 
21094  In setting signals skip the first position if it's a signal and if truncating (can only truncate to signal if route is unrestricted) - otherwise
21095  the truncated signal counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
21096 */
21097 {
21098  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
21099  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
21100  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
21101  int RearwardLinkedRouteNumber;
21102 
21103 // Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes {dropped at v2.17.0 as not used)
21104  bool SkipForwardLook = false; //allow forward look in first call
21105  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(1, Attribute, RouteStartPosition, SkipForwardLook)) // updates
21106  //Attribute to 1+ final signal value in the route for use in further linked routes
21107  {
21108  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1 (no
21109  { //linked rearwards route)
21110  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
21111  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute) //keep setting signals on each rear route until find a train or no more routes
21112  {
21113  SkipForwardLook = true; //don't want forward look for subsequent rearwards linked routes
21114  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrainInRear(2, Attribute, AllRoutes->GetFixedRouteAt(130,
21115  RearwardLinkedRouteNumber).PrefDirSize() - 1, SkipForwardLook)))
21116  {
21117  break;
21118  }
21119  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
21120  }
21121  }
21122  }
21123  else // found a train in this route (in RouteNumber) before the beginning of the route, so need to continue setting signals after the train
21124  {
21125  int TrainID, TrainPosition, BehindTrainPosition;
21126  bool FoundTrain = false, BehindTrain = false;
21127  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
21128  {
21129  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
21130  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
21131  TrainID = TrackElement.TrainIDOnElement;
21132  if(TrackElement.TrackType == Bridge)
21133  {
21134  if(PrefDirElement.XLinkPos < 2)
21135  {
21136  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21137  }
21138  else
21139  {
21140  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21141  }
21142  }
21143  if(TrainID == -1)
21144  {
21145  continue;
21146  }
21147  else
21148  {
21149  FoundTrain = true;
21150  TrainPosition = x;
21151  break;
21152  }
21153  }
21154  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then this route doesn't continue behind the train so can stop.
21155  { //If there is a linked rear route then no need to deal with signals behind train here -
21156  //if rear route is non-autosigs then no route behind train, if autosigs the train will have
21157  //set signals in rear as it passed them.
21158  for(int x = TrainPosition; x >= 0; x--) // now step back from that position until find element behind the train - ignore any
21159  { // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
21160  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
21161  // need the element behind the rearmost train.
21162  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
21163  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
21164  TrainID = TrackElement.TrainIDOnElement;
21165  if(TrackElement.TrackType == Bridge)
21166  {
21167  if(PrefDirElement.XLinkPos < 2)
21168  {
21169  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21170  }
21171  else
21172  {
21173  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21174  }
21175  }
21176  if(TrainID != -1)
21177  {
21178  continue; // still on train
21179  }
21180  else
21181  {
21182  BehindTrain = true;
21183  BehindTrainPosition = x;
21184  break;
21185  }
21186  }
21187  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
21188  // so on for as many trains as there are on this (RouteNumber) route
21189  {
21190  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // Although SkipForwardLook will be false when
21191  //SetRearwardsSignalsReturnFalseForTrainInRear is first called the forward look will find the train so Attribute will be set to 0
21192  } //for rearward signal setting
21193  }
21194  }
21195  Utilities->CallLogPop(411);
21196 }
21197 
21198 // ---------------------------------------------------------------------------
21199 
21200 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int LookBackwardsFromHere)
21201 {
21202 /* Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTruncatePosition on the route itself or on any linked routes,
21203 unless the first signal back is red, or a train on the element immediately before the start of the rearmost linked route (i.e. not on a route but about to enter the
21204 rearmost linked route) - this because train cancels route elements that it touches)
21205 */
21206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
21207  AnsiString(LookBackwardsFromHere));
21208  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber;
21209  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
21210  TPrefDirElement PrefDirElement, FirstElement;
21211  TTrackElement TrackElement;
21212  bool ExamineRoute = true;
21213 
21214  while(ExamineRoute)
21215  {
21216  for(int x = LookBackwardsFromHere; x >= 0; x--) //work back along the route from the start position
21217  {
21218  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
21219  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
21220  TrainID = TrackElement.TrainIDOnElement;
21221  if(TrackElement.TrackType == Bridge)
21222  {
21223  if(PrefDirElement.XLinkPos < 2)
21224  {
21225  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21226  }
21227  else
21228  {
21229  TrainID = TrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21230  }
21231  }
21232  if(TrainID > -1)
21233  {
21234  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
21235  {
21236  //any trains further back in route will be protected by the red signal behind the stopped train
21237  Utilities->CallLogPop(412);
21238  return(false);
21239  }
21240  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
21241  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
21242  //other way & can cancel the route
21243  {
21244  Utilities->CallLogPop(2203);
21245  return(false);
21246  }
21247  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
21248  return(true); //MovingTrainOccupyingRoute which is outside this function but also causes route locking)
21249  }
21250  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
21251  {
21252  if(TrackElement.Attribute == 0)
21253  {
21254  Utilities->CallLogPop(413);
21255  return(false); // OK, red signal in front of a train
21256  }
21257  if(TrackElement.SigAspect != TTrackElement::GroundSignal) //ignore ground signals
21258  {
21259  SignalCount++;
21260  }
21261  if(SignalCount >= 3)
21262  {
21263  Utilities->CallLogPop(414);
21264  return(false);
21265  }
21266  }
21267  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
21268  // ElinkPos because working back along PrefDir to beginning
21269  {
21270  Utilities->CallLogPop(415);
21271  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
21272  }
21273  }
21274  //now look at linked rearwards routes
21275  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
21276  LookBackwardsFromHere = CurrentRoute.PrefDirSize() - 1;
21277  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
21278  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
21279  {
21280  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
21281  ExamineRoute = true;
21282  LookBackwardsFromHere = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
21283  }
21284  else
21285  {
21286  // here check for a train on the element immediately before the first route element (i.e. not on a route but about to enter the rearmost linked route)
21287  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
21288  TrainID = PriorTrackElement.TrainIDOnElement;
21289  if(PriorTrackElement.TrackType == Bridge)
21290  {
21291  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
21292  {
21293  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit01;
21294  }
21295  else
21296  {
21297  TrainID = PriorTrackElement.TrainIDOnBridgeOrFailedPointOrigSpeedLimit23;
21298  }
21299  }
21300  if(TrainID > -1)
21301  {
21302  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
21303  {
21304  Utilities->CallLogPop(748);
21305  return(false);
21306  }
21307  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
21308  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
21309  //other way & can cancel the route
21310  {
21311  Utilities->CallLogPop(2204);
21312  return(false);
21313  }
21314  Utilities->CallLogPop(1962);
21315  return(true); //otherwise need to lock the route
21316  }
21317  ExamineRoute = false;
21318  }
21319  }
21320 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
21321 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
21322  Utilities->CallLogPop(416);
21323  return(false);
21324 }
21325 
21326 // ---------------------------------------------------------------------------
21327 
21328 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
21329  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
21330 {
21331  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
21332  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
21333  TPrefDirElement InternalPrefDirElement; // blank element
21334 
21335  PrefDirElement = InternalPrefDirElement;
21336  if(LockedRouteVector.empty())
21337  {
21338  Utilities->CallLogPop(417);
21339  return(false);
21340  }
21341 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
21342 // even if some elements have been removed from the front by a train
21343  bool InLockedRoute = false;
21344 
21345  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21346  {
21347  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
21348  {
21349  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
21350  // doesn't arise)
21351  InLockedRoute = true;
21352  break;
21353  }
21354  }
21355  if(!InLockedRoute)
21356  {
21357  Utilities->CallLogPop(418);
21358  return(false);
21359  }
21360  int RouteNumber, VectorCount = 0;
21361  TRouteType RouteType;
21362 
21363  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
21364  {
21365  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
21366  if(RouteType == NoRoute)
21367  {
21368  continue;
21369  }
21370 /* can't use this test with front truncation
21371  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
21372  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
21373  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
21374  {
21375  throw Exception
21376  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
21377  }
21378 */
21379  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
21380  {
21381  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
21382  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->RearTrackVectorPosition)
21383  {
21384  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21385  {
21386  PrefDirElement = InternalPrefDirElement;
21387  LockedVectorNumber = VectorCount;
21388  Utilities->CallLogPop(419);
21389  return(true);
21390  }
21391  }
21392  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->RearTrackVectorPosition)
21393  {
21394  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
21395  {
21396  PrefDirElement = InternalPrefDirElement;
21397  LockedVectorNumber = VectorCount;
21398  Utilities->CallLogPop(420);
21399  return(true);
21400  }
21401  else
21402  {
21403  break; // reached & tested LRVIT->RearTrackVectorPosition for a match so don't want to go any further for this route
21404  }
21405  }
21406  }
21407  VectorCount++;
21408  }
21409  Utilities->CallLogPop(421);
21410  return(false);
21411 }
21412 
21413 // ---------------------------------------------------------------------------
21414 
21416 {
21417  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
21418  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21419  {
21420  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
21421  {
21422  Utilities->CallLogPop(963);
21423  return(x);
21424  }
21425  }
21426  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
21427 }
21428 
21429 // ---------------------------------------------------------------------------
21430 
21432 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
21433 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
21434 {
21435  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21436  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21437  {
21438  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
21439  {
21440  Utilities->CallLogPop(2039);
21441  return(true);
21442  }
21443  }
21444  Utilities->CallLogPop(2040);
21445  return(false);
21446 }
21447 
21448 // ---------------------------------------------------------------------------
21449 
21451 {
21452  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
21453  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21454  {
21455  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
21456  {
21457  Utilities->CallLogPop(964);
21458  return(GetFixedRouteAt(159, x));
21459  }
21460  }
21461  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21462 }
21463 
21464 // ---------------------------------------------------------------------------
21465 
21467 {
21468  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
21469  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21470  {
21471  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
21472  {
21473  Utilities->CallLogPop(965);
21474  return(GetModifiableRouteAt(15, x));
21475  }
21476  }
21477  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
21478 }
21479 
21480 // ---------------------------------------------------------------------------
21481 
21482 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
21483 {
21484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
21485  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
21486  Utilities->SaveFileInt(OutFile, NextRouteID);
21487  for(unsigned int x = 0; x < AllRoutesSize(); x++)
21488  {
21489  TOneRoute OneRoute = GetFixedRouteAt(165, x);
21490  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
21491  OneRoute.SavePrefDirVector(6, OutFile);
21492  }
21493  Utilities->CallLogPop(1442);
21494 }
21495 
21496 // ---------------------------------------------------------------------------
21497 
21498 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
21499 {
21500  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
21501  int NumberOfRoutes;
21502 
21503  NumberOfRoutes = Utilities->LoadFileInt(InFile);
21504  NextRouteID = Utilities->LoadFileInt(InFile);
21505  for(int x = 0; x < NumberOfRoutes; x++)
21506  {
21507  TOneRoute OneRoute; // empty route
21508  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
21509  OneRoute.LoadPrefDir(2, InFile);
21511  {
21512  StoreOneRouteAfterSessionLoad(0, &OneRoute);
21513  }
21514  else
21515  {
21516  Utilities->CallLogPop(1443);
21517  return(false);
21518  }
21519  }
21520  Utilities->CallLogPop(1444);
21521  return(true);
21522 }
21523 
21524 // ---------------------------------------------------------------------------
21525 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
21526 {
21527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
21528  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
21529 
21530  if((NumberOfRoutes < 0) || (NumberOfRoutes > 10000)) //increased from 5000 to 10000 at v2.20.3 because of Jason B's WCML railway (was 304 but could get higher)
21531  {
21532  Utilities->CallLogPop(1445);
21533  return(false);
21534  }
21535  int NextID = Utilities->LoadFileInt(InFile);
21536 
21537  if((NextID < 0) || (NextID > 1000000))
21538  {
21539  Utilities->CallLogPop(1446);
21540  return(false);
21541  }
21542  for(int x = 0; x < NumberOfRoutes; x++)
21543  {
21544  int RouteID = Utilities->LoadFileInt(InFile);
21545  if((RouteID < 0) || (RouteID > 1000000)) //increased from 20000 t0 1000000 at v2.20.3 because of Jason B's WCML railway where RouteID was 22009
21546  {
21547  Utilities->CallLogPop(1447);
21548  return(false);
21549  }
21550  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
21551  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
21552  {
21553  Utilities->CallLogPop(1448);
21554  return(false);
21555  }
21556  }
21557  Utilities->CallLogPop(1449);
21558  return(true);
21559 }
21560 
21561 // ---------------------------------------------------------------------------
21562 
21563 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
21564 {
21565  // return true for a loop
21566  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
21567  AnsiString(StartPosition));
21568  if(EndPosition == StartPosition)
21569  {
21570  Utilities->CallLogPop(1839);
21571  return(true); // shouldn't happen but treat as a loop if does
21572  }
21573 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
21574  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
21575  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
21576 
21577  while(TrackIsInARoute(15, TVPos, LkPos))
21578  {
21579  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
21580  int NewLkPos = -1;
21581  if(NewTVPos > -1)
21582  {
21583  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
21584  if(NewLkPos == -1)
21585  {
21586  Utilities->CallLogPop(1840);
21587  return(true); // shouldn't arise but treat as loop if does
21588  }
21589  }
21590  else // reached a buffer or continuation
21591  {
21592  Utilities->CallLogPop(1841);
21593  return(false);
21594  }
21595 //Error found by Xeon notified by email 13/10/20.
21596 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
21597 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
21598 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
21599 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
21600 //New check added for v2.6.0
21601 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
21602 //as possible in case there are other unforeseen effects.
21603  int RouteNumber; //dummy, not used
21604  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
21605  {
21606  Utilities->CallLogPop(2241);
21607  return(false);
21608  }
21609  //now make the connected element the current element, read across the TV number and determine the exit link
21610  TVPos = NewTVPos;
21611  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
21612  {
21613  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
21614  {
21615  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
21616  {
21617  LkPos = 1;
21618  }
21619  else
21620  {
21621  LkPos = 3;
21622  }
21623  }
21624  else
21625  {
21626  LkPos = 0;
21627  }
21628  }
21629  else
21630  {
21631  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
21632  }
21633  if(TVPos == StartPosition)
21634  {
21635  Utilities->CallLogPop(1842);
21636  return(true); // it is a loop
21637  }
21638  }
21639  Utilities->CallLogPop(1843);
21640  return(false); // reached end of route so not a loop
21641 }
21642 
21643 // ---------------------------------------------------------------------------
21644 
21645 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21646 /*
21647  Track geometry allows diagonals to cross without occupying the same track element, so when
21648  route plotting it is necessary to check if there is an existing route or a train on such a crossing
21649  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
21650  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21651  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21652  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21653  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21654  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21655  Each of these is examined in turn for each route element in the relevant position.
21656 
21657  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
21658  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
21659  that returns false in all cases (including elements & links not present) except train present.
21660 */
21661 {
21662  int TrainID; // not used in this function
21663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
21664  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
21665  TPrefDirElement TempPrefDirElement;
21666  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21667  //first check that this element with DiagonalLinkNumber is not itself a budder/Gap/Continuation
21668  TTrackElement TE = Track->GetTrackElementFromTrackMap(7, HLoc, VLoc);
21669  if(((TE.TrackType == Buffers) || (TE.TrackType == GapJump) || (TE.TrackType == Continuation)) && (TE.Link[0] == DiagonalLinkNumber))
21670  {
21671  Utilities->CallLogPop(2748);
21672  return(false);
21673  }
21674  int H = HLoc - 1;
21675  int V = VLoc;
21676  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, H, V, SecondPair);
21677  if(FirstPair.first > -1)
21678  {
21679  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
21680  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(0, H, V, 3)))
21681  {
21682  Utilities->CallLogPop(310);
21683  return(true);
21684  }
21685  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(1, H, V, 9)))
21686  {
21687  Utilities->CallLogPop(311);
21688  return(true);
21689  }
21690  }
21691  if(SecondPair.first > -1)
21692  {
21693  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
21694  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(2, H, V, 3)))
21695  {
21696  Utilities->CallLogPop(312);
21697  return(true);
21698  }
21699  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(3, H, V, 9)))
21700  {
21701  Utilities->CallLogPop(313);
21702  return(true);
21703  }
21704  }
21705  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, H, V, 3, TrainID) && !(Track->DiagAtLinkIsBufGapCont(16, H, V, 3)))
21706  || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, H, V, 9, TrainID) && !(Track->DiagAtLinkIsBufGapCont(17, H, V, 9))))
21707  {
21708  Utilities->CallLogPop(1997);
21709  return(true);
21710  }
21711  H = HLoc;
21712  V = VLoc - 1;
21713  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, H, V, SecondPair);
21714  if(FirstPair.first > -1)
21715  {
21716  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
21717  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(4, H, V, 7)))
21718  {
21719  Utilities->CallLogPop(314);
21720  return(true);
21721  }
21722  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(5, H, V, 9)))
21723  {
21724  Utilities->CallLogPop(315);
21725  return(true);
21726  }
21727  }
21728  if(SecondPair.first > -1)
21729  {
21730  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
21731  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(6, H, V, 7)))
21732  {
21733  Utilities->CallLogPop(316);
21734  return(true);
21735  }
21736  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(7, H, V, 9)))
21737  {
21738  Utilities->CallLogPop(317);
21739  return(true);
21740  }
21741  }
21742  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, H, V, 7, TrainID) && !(Track->DiagAtLinkIsBufGapCont(18, H, V, 7)))
21743  || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, H, V, 9, TrainID) && !(Track->DiagAtLinkIsBufGapCont(19, H, V, 9))))
21744  {
21745  Utilities->CallLogPop(1998);
21746  return(true);
21747  }
21748  H = HLoc + 1;
21749  V = VLoc;
21750  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, H, V, SecondPair);
21751  if(FirstPair.first > -1)
21752  {
21753  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
21754  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(8, H, V, 1)))
21755  {
21756  Utilities->CallLogPop(318);
21757  return(true);
21758  }
21759  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(9, H, V, 7)))
21760  {
21761  Utilities->CallLogPop(319);
21762  return(true);
21763  }
21764  }
21765  if(SecondPair.first > -1)
21766  {
21767  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
21768  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(10, H, V, 1)))
21769  {
21770  Utilities->CallLogPop(320);
21771  return(true);
21772  }
21773  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(11, H, V, 7)))
21774  {
21775  Utilities->CallLogPop(321);
21776  return(true);
21777  }
21778  }
21779  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, H, V, 1, TrainID) && !(Track->DiagAtLinkIsBufGapCont(20, H, V, 1)))
21780  || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, H, V, 7, TrainID) && !(Track->DiagAtLinkIsBufGapCont(21, H, V, 7))))
21781  {
21782  Utilities->CallLogPop(1999);
21783  return(true);
21784  }
21785  H = HLoc;
21786  V = VLoc + 1;
21787  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, H, V, SecondPair);
21788  if(FirstPair.first > -1)
21789  {
21790  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
21791  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(12, H, V, 1)))
21792  {
21793  Utilities->CallLogPop(322);
21794  return(true);
21795  }
21796  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(13, H, V, 3)))
21797  {
21798  Utilities->CallLogPop(323);
21799  return(true);
21800  }
21801  }
21802  if(SecondPair.first > -1)
21803  {
21804  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
21805  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(14, H, V, 1)))
21806  {
21807  Utilities->CallLogPop(324);
21808  return(true);
21809  }
21810  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(15, H, V, 3)))
21811  {
21812  Utilities->CallLogPop(325);
21813  return(true);
21814  }
21815  }
21816  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, H, V, 1, TrainID) && !(Track->DiagAtLinkIsBufGapCont(22, H, V, 1)))
21817  || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, H, V, 3, TrainID) && !(Track->DiagAtLinkIsBufGapCont(23, H, V, 3))))
21818  {
21819  Utilities->CallLogPop(2000);
21820  return(true);
21821  }
21822  Utilities->CallLogPop(326);
21823  return(false);
21824 }
21825 
21826 // ---------------------------------------------------------------------------
21827 
21828 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
21829 /*
21830  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
21831  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
21832  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
21833  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
21834  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
21835  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
21836  Each of these is examined in turn for each route element in the relevant position.
21837 */
21838 {
21839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
21840  "," + AnsiString(DiagonalLinkNumber));
21841  TPrefDirElement TempPrefDirElement;
21842  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
21843  //first check that this element with DiagonalLinkNumber is not itself a budder/Gap/Continuation
21844  TTrackElement TE = Track->GetTrackElementFromTrackMap(8, HLoc, VLoc);
21845  if(((TE.TrackType == Buffers) || (TE.TrackType == GapJump) || (TE.TrackType == Continuation)) && (TE.Link[0] == DiagonalLinkNumber))
21846  {
21847  Utilities->CallLogPop(2749);
21848  return(false);
21849  }
21850  int H = HLoc - 1;
21851  int V = VLoc;
21852  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, H, V, SecondPair);
21853  if(FirstPair.first > -1)
21854  {
21855  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
21856  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(24, H, V, 3)))
21857  {
21858  Utilities->CallLogPop(2010);
21859  return(true);
21860  }
21861  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(25, H, V, 9)))
21862  {
21863  Utilities->CallLogPop(2011);
21864  return(true);
21865  }
21866  }
21867  if(SecondPair.first > -1)
21868  {
21869  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
21870  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(26, H, V, 3)))
21871  {
21872  Utilities->CallLogPop(2012);
21873  return(true);
21874  }
21875  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(27, H, V, 9)))
21876  {
21877  Utilities->CallLogPop(2013);
21878  return(true);
21879  }
21880  }
21881  H = HLoc;
21882  V = VLoc - 1;
21883  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, H, V, SecondPair);
21884  if(FirstPair.first > -1)
21885  {
21886  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
21887  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(28, H, V, 7)))
21888  {
21889  Utilities->CallLogPop(2014);
21890  return(true);
21891  }
21892  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(29, H, V, 9)))
21893  {
21894  Utilities->CallLogPop(2015);
21895  return(true);
21896  }
21897  }
21898  if(SecondPair.first > -1)
21899  {
21900  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
21901  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(30, H, V, 7)))
21902  {
21903  Utilities->CallLogPop(2016);
21904  return(true);
21905  }
21906  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)) && !(Track->DiagAtLinkIsBufGapCont(31, H, V, 9)))
21907  {
21908  Utilities->CallLogPop(2017);
21909  return(true);
21910  }
21911  }
21912  H = HLoc + 1;
21913  V = VLoc;
21914  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, H, V, SecondPair);
21915  if(FirstPair.first > -1)
21916  {
21917  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
21918  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(32, H, V, 1)))
21919  {
21920  Utilities->CallLogPop(2018);
21921  return(true);
21922  }
21923  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(33, H, V, 7)))
21924  {
21925  Utilities->CallLogPop(2019);
21926  return(true);
21927  }
21928  }
21929  if(SecondPair.first > -1)
21930  {
21931  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
21932  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(34, H, V, 1)))
21933  {
21934  Utilities->CallLogPop(2020);
21935  return(true);
21936  }
21937  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)) && !(Track->DiagAtLinkIsBufGapCont(35, H, V, 7)))
21938  {
21939  Utilities->CallLogPop(2021);
21940  return(true);
21941  }
21942  }
21943  H = HLoc;
21944  V = VLoc + 1;
21945  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, H, V, SecondPair);
21946  if(FirstPair.first > -1)
21947  {
21948  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
21949  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(36, H, V, 1)))
21950  {
21951  Utilities->CallLogPop(2022);
21952  return(true);
21953  }
21954  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(37, H, V, 3)))
21955  {
21956  Utilities->CallLogPop(2023);
21957  return(true);
21958  }
21959  }
21960  if(SecondPair.first > -1)
21961  {
21962  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
21963  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)) && !(Track->DiagAtLinkIsBufGapCont(38, H, V, 1)))
21964  {
21965  Utilities->CallLogPop(2024);
21966  return(true);
21967  }
21968  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)) && !(Track->DiagAtLinkIsBufGapCont(39, H, V, 3)))
21969  {
21970  Utilities->CallLogPop(2025);
21971  return(true);
21972  }
21973  }
21974  Utilities->CallLogPop(2026);
21975  return(false);
21976 }
21977 
21978 // ---------------------------------------------------------------------------
21979 
21980 
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:9747
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:696
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:481
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:20048
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1334
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:953
TTrack::MarkOneLengthandSpeed
void MarkOneLengthandSpeed(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:10217
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:468
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:12640
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:682
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:749
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:37
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:632
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:584
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:12613
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:441
TTrack::ResetTSRs
void ResetTSRs(int Caller)
Called on exit from operation to reset failed to false for all simple track elements & clear TSRVecto...
Definition: TrackUnit.cpp:4894
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:575
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:51
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:81
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:357
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:894
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5769
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:14158
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:791
TFixedTrackPiece
Definition: TrackUnit.h:85
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1750
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:214
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:817
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:428
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:944
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:20643
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:94
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:810
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:247
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:945
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:10651
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:812
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:21054
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:956
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1388
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:513
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:809
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:600
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:721
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:14682
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:778
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:639
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:827
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:439
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:14198
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:698
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Uses 'ChangeTransparentColour' method to change each graphic in turn.
Definition: GraphicUnit.cpp:3974
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:719
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:399
PerfLogForm
TPerfLogForm * PerfLogForm
Definition: PerfLogUnit.cpp:11
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:458
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:900
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:807
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:289
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7581
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:471
TAllRoutes::SearchAllRoutesAndTruncate
bool SearchAllRoutesAndTruncate(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses TruncateRoute to see if the element at H & V is present in that...
Definition: TrackUnit.cpp:20010
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:103
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:703
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1730
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:732
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5921
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7482
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5948
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1544
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:595
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1691
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:69
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:845
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:866
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1978
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:933
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:11104
TRailGraphics::FGSig70
Graphics::TBitmap * FGSig70
Definition: GraphicUnit.h:928
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:625
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:631
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:942
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:21828
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:441
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1721
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:71
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:616
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2954
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:488
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:560
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:6101
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:747
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:691
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:464
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Definition: TrackUnit.h:155
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8509
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
Definition: TrackUnit.h:1554
TUtilities::RedLowFlag
bool RedLowFlag
Sets Red = low values for heatmaps.
Definition: Utilities.h:77
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:459
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:654
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:20481
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:782
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:587
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:685
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:13937
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:364
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7967
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:487
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:405
TTrackElement::StationEntryStopLinkPos3
int StationEntryStopLinkPos3
Definition: TrackUnit.h:155
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:11071
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9762
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:15347
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:49
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:17798
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:585
TTrack::TActiveLevelCrossing::TActiveLevelCrossing
TActiveLevelCrossing()
constructor, sets default values
Definition: TrackUnit.cpp:1140
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:20843
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:876
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:874
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:498
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1671
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:892
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:552
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:13741
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:163
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:517
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4644
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3792
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:692
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:850
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1568
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:463
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:601
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:779
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:470
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:815
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:8324
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:447
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:196
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:681
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:604
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1045
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4804
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1348
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6765
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:11879
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:673
TRailGraphics::FGSig71
Graphics::TBitmap * FGSig71
Definition: GraphicUnit.h:929
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:521
TRailGraphics::FGSig69
Graphics::TBitmap * FGSig69
Definition: GraphicUnit.h:927
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:887
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3668
Unused
@ Unused
Definition: TrackUnit.h:68
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:606
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:636
TTrack::OneStationLongEnoughForSplit
bool OneStationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:11353
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1347
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:494
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:724
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:21328
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2987
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:789
TTrack::ResetAllTrainIDsAndFailedPointOrigSpeedLimits
void ResetAllTrainIDsAndFailedPointOrigSpeedLimits(int Caller)
Definition: TrackUnit.cpp:7953
TRailGraphics::FSig75
Graphics::TBitmap * FSig75
Definition: GraphicUnit.h:925
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:230
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:21525
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:583
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1729
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1566
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1658
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:212
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:954
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:35
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:781
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:445
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:839
TTrack::SimpleVector
TSimpleVector SimpleVector
vector of simple element track vector positions
Definition: TrackUnit.h:823
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3392
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:17110
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:35
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:222
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:796
TUtilities::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
< used to send no platforms warning once only
Definition: Utilities.h:87
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:688
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:504
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8801
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:14003
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:811
Simple
@ Simple
Definition: TrackUnit.h:68
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:448
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:79
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:482
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:813
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:3003
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:734
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1045
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:20591
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:794
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:838
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:429
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1415
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:725
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:14254
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:4020
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1784
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:614
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:6061
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:689
TTrain
Definition: TrainUnit.h:315
TTrack::FailedGroundSigTable
TSigElement FailedGroundSigTable[8]
table of failed signals added at v2.13.0
Definition: TrackUnit.h:747
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:384
TTrack::SetNonStationStopLinkEntryPosses
void SetNonStationStopLinkEntryPosses(int Caller)
similar to SetStationEntryStopLinkPosses but for non-station named elements
Definition: TrackUnit.cpp:10867
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:15202
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:508
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12654
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:497
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:580
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:579
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:861
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:635
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7982
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:420
TPerfLogForm::PerformanceLog
void PerformanceLog(int Caller, AnsiString Statement)
Send Statement to the performance log on screen and to the file.
Definition: PerfLogUnit.cpp:32
TUtilities::DefaultTrackLength
int DefaultTrackLength
length of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:95
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:351
GapJump
@ GapJump
Definition: TrackUnit.h:68
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:447
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:809
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:20951
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:875
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7728
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:153
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:476
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:957
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:462
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:153
TTrack::Raising
@ Raising
Definition: TrackUnit.h:616
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:647
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:577
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:11209
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:588
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen (as viewpoint moves down [railway moves up] this offset i...
Definition: DisplayUnit.h:79
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1570
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1532
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:717
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:370
TTrack::IsElementDefaultLengthAndSpeed
bool IsElementDefaultLengthAndSpeed(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
True if track at link positions [0] & [1] if FirstTrack true, else that at [2] & [3] in TrackElement ...
Definition: TrackUnit.cpp:10555
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:754
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:589
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:813
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:390
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:780
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:457
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:734
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1424
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:6349
End
@ End
Definition: TrackUnit.h:78
TUserGraphicItem
Definition: DisplayUnit.h:32
TUtilities::FixedMinRepairTime
int FixedMinRepairTime
Definition: Utilities.h:72
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1572
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:687
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:862
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:627
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:9155
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:883
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:940
TDisplay::GetImage
TImage * GetImage()
Return a pointer to the screen image.
Definition: DisplayUnit.h:139
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:42
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:572
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:11318
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1058
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:307
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:819
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:750
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:72
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:819
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:597
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:950
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:127
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:742
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:496
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:777
TUtilities::Format96HHMMSS
AnsiString Format96HHMMSS(TDateTime DateTime)
formats a TDateTime into an AnsiString of the form hh:mm:ss where hh runs from 00 to 95 & resets when...
Definition: Utilities.cpp:812
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3994
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:1026
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:878
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:1027
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:234
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:445
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:529
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:720
SignalPost
@ SignalPost
Definition: TrackUnit.h:68
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9896
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1039
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:466
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:19998
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:511
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:797
TOneRoute::SetRearwardsSignalsReturnFalseForTrainInRear
bool SetRearwardsSignalsReturnFalseForTrainInRear(int Caller, int &Attribute, int PrefDirVectorStartPosition, bool SkipForwardLook) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:18668
TAllRoutes::TAllRoutesVectorIterator
std::vector< TOneRoute >::iterator TAllRoutesVectorIterator
Definition: TrackUnit.h:1685
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1090
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1695
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:811
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:846
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7996
TRailGraphics::FGSig68
Graphics::TBitmap * FGSig68
Definition: GraphicUnit.h:926
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:461
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:677
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:408
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:7174
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:652
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:232
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:495
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:704
TRailGraphics::FSig71
Graphics::TBitmap * FSig71
Definition: GraphicUnit.h:921
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:37
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:9194
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:943
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:836
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker to display all routes, with RouteCall set to identify a route call,...
Definition: TrackUnit.cpp:19983
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:775
Concourse
@ Concourse
Definition: TrackUnit.h:69
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:595
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:676
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:831
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:820
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:77
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:14971
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:14708
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:235
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:733
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:931
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:67
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:507
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4729
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1928
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:98
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:432
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:833
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:438
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:848
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:485
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:613
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:823
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:439
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:499
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:36
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:791
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:477
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:96
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:435
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:835
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:594
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:12082
TUtilities::NoPlatsMessageSent
bool NoPlatsMessageSent
Definition: Utilities.h:85
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:20796
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4990
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:163
TRailGraphics::HeatMapGraphic
Graphics::TBitmap * HeatMapGraphic
Definition: GraphicUnit.h:1034
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1947
TTrack::MultiplayerOverlayMap
TMultiplayerOverlayMap MultiplayerOverlayMap
Definition: TrackUnit.h:801
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:693
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:808
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:961
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:769
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:567
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:91
TAllRoutes::Route2MultiMap
TRoute2MultiMap Route2MultiMap
the map that stores the elements of all routes on the railway (see TRoute2MultiMap for more info)
Definition: TrackUnit.h:1754
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:605
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:739
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:854
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:470
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:662
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:12327
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:21431
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:595
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1056
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:630
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2971
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:729
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1578
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:16223
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7609
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8991
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7688
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:686
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:740
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5972
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:699
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:679
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
Definition: TrainUnit.h:330
TOneRoute::QuitAllRecursiveSearchesFlag
bool QuitAllRecursiveSearchesFlag
< limit to the number of elements searched in attempting to find a route in on leg
Definition: TrackUnit.h:1558
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:690
TOneRoute::ReclaimSignalsForNonAutoSigRoutes
void ReclaimSignalsForNonAutoSigRoutes(int caller, TPrefDirElement LastPDElement, TPrefDirElement FirstPDElement)
Adds signal to front/end of green or red routes when blue route truncated or removed.
Definition: TrackUnit.cpp:19503
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1350
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:878
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:822
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:514
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:821
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:474
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:14342
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:785
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:886
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:13477
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1696
TTrack::LengthandSpeedMarker
void LengthandSpeedMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9931
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:87
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1748
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
gives a delay od Msec value;
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:48
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:941
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:607
TTrack::TSRVector
TFailedElementVector TSRVector
vector of failed points with track vector positions & repair times for use in failure handling (new a...
Definition: TrackUnit.h:797
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:13970
TTrack::TInfrastructureFailureEntry::TVPos
int TVPos
Definition: TrackUnit.h:717
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:671
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:19629
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3769
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:14661
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:12388
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1830
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:783
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:943
TRailGraphics::GetHeatMapColor
void GetHeatMapColor(int Caller, float value, int *red, int *green, int *blue)
Definition: GraphicUnit.cpp:4923
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:500
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:586
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:6155
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1028
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:13790
Under
@ Under
Definition: TrackUnit.h:78
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:454
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:831
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:715
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:631
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:3026
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:12666
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:12985
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:890
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:436
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:137
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:56
Lead
@ Lead
Definition: TrackUnit.h:78
TUtilities::FailureMode
TFailureMode FailureMode
specifies whether no failures or minor, moderate or major random failures are to be applied (added at...
Definition: Utilities.h:127
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:6020
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1864
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:14909
TTrack::PlotContinuation
void PlotContinuation(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a continuation on screen, may have overlays if a multiplayer session.
Definition: TrackUnit.cpp:6232
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:897
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:558
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:262
TRailGraphics::ChangeForegroundColour2
void ChangeForegroundColour2(int Caller, Graphics::TBitmap *BitmapIn, Graphics::TBitmap *BitmapOut, TColor NewForegroundColour, TColor BackgroundColour)
New function to do the same as the above but with fewer pixel changes - for use in LoadSession to avo...
Definition: GraphicUnit.cpp:3674
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5812
TOneRoute::TruncateRoute
void TruncateRoute(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:18915
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6746
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourses, footcrossings (the only active elements...
Definition: TrackUnit.h:88
TUtilities::SignalChangeEventsPerFailure
int SignalChangeEventsPerFailure
number of signal changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:101
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1379
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9690
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:472
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:473
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:598
TTrack::TInfrastructureFailureEntry
Definition: TrackUnit.h:716
TTrack::Up
@ Up
Definition: TrackUnit.h:616
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:882
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:833
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:590
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:11332
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:960
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1526
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:380
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8958
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1689
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:763
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:208
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:19716
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1678
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:367
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:800
Crossover
@ Crossover
Definition: TrackUnit.h:68
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6632
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:479
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:450
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:835
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:642
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8904
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:802
TRailGraphics::BlackOctagon
Graphics::TBitmap * BlackOctagon
Definition: GraphicUnit.h:577
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7637
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:10624
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:456
Signal
@ Signal
Definition: TrackUnit.h:78
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:577
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:595
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:465
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:799
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:20285
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1598
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:13840
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:510
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:12266
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4813
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:575
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:11304
TGraphicElement::Width
int Width
Definition: TrackUnit.h:443
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:21200
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:524
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:21415
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:20111
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:805
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:492
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:849
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:589
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:662
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:451
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or ' ' (CRLF) accepted as delimiters), returns true for succes...
Definition: Utilities.cpp:553
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:790
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:34
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:15757
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:664
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4302
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2487
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:697
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:469
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9830
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks, bool PerformNameSearch)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2229
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to display EveryPrefDir - red for unidirectional PrefDir & gre...
Definition: TrackUnit.cpp:13608
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:608
TTrack::FailedSignalsVector
TFailedElementVector FailedSignalsVector
Definition: TrackUnit.h:797
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:411
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:881
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:970
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5996
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:21498
FNil
@ FNil
Definition: Utilities.h:43
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:587
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1570
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:947
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:788
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1560
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:847
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:7335
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:475
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1069
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1071
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:518
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:8168
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:19808
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:665
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:426
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7710
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:804
Erase
@ Erase
Definition: TrackUnit.h:69
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:851
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:402
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:484
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5617
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:831
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:831
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:878
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:595
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:14731
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:623
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:12178
Parapet
@ Parapet
Definition: TrackUnit.h:69
HiddenDisplay
TDisplay * HiddenDisplay
The object pointer for the internal hidden display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:55
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:452
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:19957
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:123
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:805
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:1030
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:277
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:9499
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:19781
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:382
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:871
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:831
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:20819
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:610
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:952
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
< map of coupled continuations
Definition: TrackUnit.h:803
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:803
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:151
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:483
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:826
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:249
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:554
TRailGraphics::FSig72
Graphics::TBitmap * FSig72
Definition: GraphicUnit.h:922
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1074
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:742
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:818
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:17364
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:843
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:139
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:210
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:12416
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track display function, including direction markers.
Definition: TrackUnit.cpp:13535
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:509
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1328
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:501
TRailGraphics::FSig70
Graphics::TBitmap * FSig70
Definition: GraphicUnit.h:920
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:19744
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:616
TRailGraphics::FSig74
Graphics::TBitmap * FSig74
Definition: GraphicUnit.h:924
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:480
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:751
TTrack
Definition: TrackUnit.h:553
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1387
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:878
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1418
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:20967
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:287
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute, int StartPos) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:18568
TAllRoutes::LockedRouteRearTrackVectorPosition
unsigned int LockedRouteRearTrackVectorPosition
Definition: TrackUnit.h:1728
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1665
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8478
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:640
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:593
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:860
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:670
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:746
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:869
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:130
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:825
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:520
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:705
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:208
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:20459
TRailGraphics::FGSig74
Graphics::TBitmap * FGSig74
Definition: GraphicUnit.h:932
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:216
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:3106
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:455
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:10327
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:946
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6526
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:159
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:592
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:744
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:163
TTrackElement::TTrackElement
TTrackElement()
Constructor for non-specific default element. Use high neg numbers for 'unset' h & v as can go high n...
Definition: TrackUnit.h:169
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:864
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:811
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2707
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:206
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1663
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:8132
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:486
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:13323
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:14101
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:591
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1532
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:11241
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8867
IDInt
Definition: TrackUnit.h:502
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:3014
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:593
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:21466
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:617
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:798
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4617
TDisplay
Definition: DisplayUnit.h:50
TRailGraphics::FGSig72
Graphics::TBitmap * FGSig72
Definition: GraphicUnit.h:930
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10991
TRailGraphics::FSig69
Graphics::TBitmap * FSig69
Definition: GraphicUnit.h:919
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5360
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:149
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:923
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:792
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:841
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:445
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:21563
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1154
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9613
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:575
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:99
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8079
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1329
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:229
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:157
TTrackElement::Failed
bool Failed
New parameter added at v2.13.0 for failed points, signals & TSRs.
Definition: TrackUnit.h:143
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:906
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:14411
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:787
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:750
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:385
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:651
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:214
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:397
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:867
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:15554
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1733
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:186
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:132
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:787
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:8047
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:637
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:828
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:801
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:735
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:151
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:913
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:774
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1543
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:858
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route (this will be truncated...
Definition: TrackUnit.h:1669
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:855
TOneRoute::RouteSearchLimitOneLeg
static const int RouteSearchLimitOneLeg
< limit to the total number of elements searched in attempting to find a route
Definition: TrackUnit.h:1556
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1679
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:441
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4912
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:590
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:9439
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:760
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:16916
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1357
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:736
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:439
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:14837
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:832
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1335
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:14612
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:155
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:722
Points
@ Points
Definition: TrackUnit.h:68
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:743
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:20532
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:873
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:12249
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:414
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:602
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:840
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:503
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4324
Trail
@ Trail
Definition: TrackUnit.h:78
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:19693
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9672
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:781
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1900
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:502
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:41
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:824
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all signals appropriately. Also called when a new train is added a...
Definition: TrackUnit.cpp:18458
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:837
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:667
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:423
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:745
Continuation
@ Continuation
Definition: TrackUnit.h:68
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1065
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:36
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7926
GraphicUnit.h
PerfLogUnit.h
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3869
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:6252
TOnePrefDir::FindLinkingCompatiblePrefDir
bool FindLinkingCompatiblePrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that is compatible and links to another element at given vector number and l...
Definition: TrackUnit.cpp:14509
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:87
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:595
TTrack::ThisLocationLongEnoughForSplit
bool ThisLocationLongEnoughForSplit(int Caller, AnsiString HeadCode, int TrainID, AnsiString LocationName, int LeadElement, int LeadExitPos, int MidElement, int MidEntryPos, int &FrontTrainFrontPos, int &FrontTrainRearPos, int &RearTrainFrontPos, int &RearTrainRearPos, bool &TemporaryDelay)
checks if the track that the train is on is long enough for a split, returns false if not,...
Definition: TrackUnit.cpp:11624
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:360
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9719
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:872
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:880
TTrack::DiagAtLinkIsBufGapCont
bool DiagAtLinkIsBufGapCont(int Caller, int H, int V, int LinkIn)
checks if Link[0] for a diagonal buffer, gap or continuation is a buffer etc. used in fouled diagonal...
Definition: TrackUnit.cpp:12590
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:888
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:13366
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:581
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:842
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:772
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:877
TTrack::TInfrastructureFailureEntry::FailureTime
TDateTime FailureTime
Definition: TrackUnit.h:718
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:439
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:595
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1054
TTrack::FailedPointsVector
TFailedElementVector FailedPointsVector
Definition: TrackUnit.h:797
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3486
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:443
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:893
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1563
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:90
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:460
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:708
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:718
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:744
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1727
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:948
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:373
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:271
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:748
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:355
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:856
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:21645
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:491
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:14306
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1043
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:489
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:786
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1534
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1047
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:85
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:54
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:354
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:453
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:793
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:635
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:907
TRailGraphics::FGSig75
Graphics::TBitmap * FGSig75
Definition: GraphicUnit.h:933
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0),...
Definition: TrackUnit.cpp:4873
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:891
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:20431
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1760
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:9005
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:718
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:701
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:125
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:596
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:815
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:672
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:233
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:830
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:712
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1389
TOneRoute::SignalHasFailed
bool SignalHasFailed(int Caller)
Check incorporated in route search routines after have found a legitimate route, returns false for si...
Definition: TrackUnit.cpp:19835
TTrack::TInfrastructureFailureEntry::RepairTime
TDateTime RepairTime
Definition: TrackUnit.h:719
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:21482
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:585
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1910
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0), failed to false & clear Fa...
Definition: TrackUnit.cpp:4855
Connection
@ Connection
Definition: TrackUnit.h:78
TRailGraphics::FGSig73
Graphics::TBitmap * FGSig73
Definition: GraphicUnit.h:931
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3846
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:363
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
Definition: TrackUnit.h:1735
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, TOnePrefDir *TempEveryPrefDir, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:2005
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:1031
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:752
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:505
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:18271
TTrack::PopulateSimpleVector
void PopulateSimpleVector(int Caller)
clear then add all simple element track vector positions to the vector, added at v2....
Definition: TrackUnit.cpp:12574
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:13184
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:726
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:829
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8931
TTrack::RepairTSR
void RepairTSR(TFailedElementVector::iterator FPVIt)
remove TSR, added at v2.13.0
Definition: TrackUnit.cpp:12546
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:879
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1052
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:20741
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:20697
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:7408
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:567
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:11907
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:711
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:870
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:738
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1416
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:903
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:490
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller, int &NewFailedPointsTVPos) const
Definition: TrackUnit.cpp:18480
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:6040
TTrack::OneLengthOrSpeedHeatMapColour
void OneLengthOrSpeedHeatMapColour(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
Heatmap function for a single trackelement.
Definition: TrackUnit.cpp:9978
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:863
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:727
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:449
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:263
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit01
Definition: TrackUnit.h:157
TTrackElement::StationEntryStopLinkPos4
int StationEntryStopLinkPos4
Used for track at platforms ( 1 & 2) and non-station named locations (1 - 4) to mark the train front ...
Definition: TrackUnit.h:155
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:439
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:10678
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:577
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:740
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:755
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:19970
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:5022
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:807
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2882
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:694
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:8007
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:391
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3248
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:379
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:859
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:134
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:884
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:376
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:18429
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:633
TTrack::LengthOrSpeedHeatMap
void LengthOrSpeedHeatMap(int Caller, bool Length, TDisplay *Disp)
Heatmap function for all track elements - unused.
Definition: TrackUnit.cpp:9952
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen (as viewpoint moves to the right [railway moves left] t...
Definition: DisplayUnit.h:77
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:15101
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:319
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:353
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:777
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:609
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:698
TUtilities::MaxRandomRepairTime
int MaxRandomRepairTime
Definition: Utilities.h:71
TPrefDirElement::GetRouteColour
int GetRouteColour(Graphics::TBitmap *EXG)
finds the route colour for a specific prefdir element with EXGraphicPtr EXG
Definition: TrackUnit.cpp:1107
TTrack::RepairFailedSignals
void RepairFailedSignals(TFailedElementVector::iterator FPVIt)
restore signal to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12484
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:633
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:398
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:493
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1329
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:659
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:467
TRailGraphics::FSig73
Graphics::TBitmap * FSig73
Definition: GraphicUnit.h:923
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:669
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:936
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:644
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:12745
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:459
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:439
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:519
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:955
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:102
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1530
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:203
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:9054
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:817
TDisplay::WarningLog
void WarningLog(int Caller, AnsiString Statement)
Display warning message Statement in the bottom left hand warning position and scroll other messages ...
Definition: DisplayUnit.cpp:524
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1808
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:9236
TTrack::LengthHeatMapFlag
bool LengthHeatMapFlag
true when plotting a length heatmap
Definition: TrackUnit.h:765
TUtilities::PointChangeEventsPerFailure
int PointChangeEventsPerFailure
number of points changes between failures - reciprocal of failure probability per change
Definition: Utilities.h:99
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:645
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:591
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:728
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:14808
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:21450
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:145
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:615
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1386
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4566
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:821
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4746
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7870
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:530
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1060
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6672
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:1028
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:714
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:68
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:844
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:646
TRailGraphics::FSig68
Graphics::TBitmap * FSig68
Definition: GraphicUnit.h:918
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7665
Platform
@ Platform
Definition: TrackUnit.h:68
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1418
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:216
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:671
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:889
TTrack::SpeedHeatMapFlag
bool SpeedHeatMapFlag
true when plotting a speed heatmap
Definition: TrackUnit.h:767
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:785
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:756
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4771
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:795
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1673
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1067
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:784
TTrack::RepairFailedPoints
void RepairFailedPoints(TFailedElementVector::iterator FPVIt)
restore points to unfailed state, added at v2.13.0
Definition: TrackUnit.cpp:12516
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:958
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8429
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:684
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1342
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:814
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:849
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9870
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1041
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:773
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:12143
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1815
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:834
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:113
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:643
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1532
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:352
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:17337
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7853
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:825
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:153
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:799
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:169
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:697
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1534
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:620
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6689
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:728
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3746
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:776
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:662
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:101
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:115
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:588
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:806
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:761
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:12069
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:793
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:885
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, bool RecursiveCall)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:17753
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:853
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:153
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: TrackUnit.h:41
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:685
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:949
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:305
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:713
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:629
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:732
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:83
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1073
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:417
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:586
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag = 1, top = 2, top rh diag = 3,...
Definition: TrackUnit.h:92
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:692
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:829
RouteCall
@ RouteCall
Definition: TrackUnit.h:1335
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:392
TTrackElement::TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
int TrainIDOnBridgeOrFailedPointOrigSpeedLimit23
Definition: TrackUnit.h:157
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12679
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:865
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
Definition: TextUnit.cpp:269
TUtilities::DefaultTrackSpeedLimit
int DefaultTrackSpeedLimit
speed limit of each track element before being changed within the program (can be changed in config....
Definition: Utilities.h:97
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:611
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:506
NotSet
@ NotSet
Definition: TrackUnit.h:78
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:675
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:21013
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:89
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:267
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:395
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:612
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:599
TTrack::FailedSigTable
TSigElement FailedSigTable[8]
Definition: TrackUnit.h:747
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:12098
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:11073
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:680
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:536
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:206
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:795
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int TrackPos, int LinkPos, int OwnTrainID)
True if another train on LinkPos track of element at TrackPos, whether bridge or not,...
Definition: TrackUnit.cpp:12036
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:951
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6590
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:163
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:69
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:959
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag, bool RecursiveCall)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:16259
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:753
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:12691
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1391
TAllRoutes::TLockedRouteClass::RearTrackVectorPosition
unsigned int RearTrackVectorPosition
the TrackVector position of the rearmost element selected for truncation (this will be truncated)
Definition: TrackUnit.h:1667
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:396
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:147
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1580
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:857
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:741
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:827
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:712
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:577
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:634
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:11064
Bridge
@ Bridge
Definition: TrackUnit.h:68
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:868
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:444
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1329
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:816
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:528
Gap
@ Gap
Definition: TrackUnit.h:78
Buffers
@ Buffers
Definition: TrackUnit.h:68
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:18187
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:709
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:105
CrossConn
@ CrossConn
Definition: TrackUnit.h:78
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:12703
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:478
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4683
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:12626
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:852
TTrack::OneNonStationLongEnoughForSplit
bool OneNonStationLongEnoughForSplit(int Caller, AnsiString LocationName)
As below but here allow points & crossovers.
Definition: TrackUnit.cpp:11460